1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-05 05:34:18 +02:00

Compare commits

..

24 Commits

Author SHA1 Message Date
Matthieu Gallien
cd934ba80c Merge pull request #3656 from nextcloud/backport/3655/stable-3.3
[stable-3.3] Return the login name instead of user id
2021-08-12 15:29:22 +02:00
Felix Weilbach
5202df4407 Return the login name instead of user id
App password and login name need to match. If authResult() returns the
user id the user id will be stored in webdav_user

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-12 13:17:57 +00:00
Felix Weilbach
99bcf30f77 Merge pull request #3650 from nextcloud/bump-3.3.1
Bump to version 3.3.1
2021-08-12 10:36:42 +02:00
Felix Weilbach
56e8561e64 Bump to version 3.3.1
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-12 10:35:11 +02:00
Nextcloud bot
05fef8e463 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-12 03:53:16 +00:00
Matthieu Gallien
6f5c61e442 Merge pull request #3648 from nextcloud/backport/3646/stable-3.3
[stable-3.3] Enforce fetching of user id
2021-08-11 18:51:29 +02:00
Felix Weilbach
1e28185ee9 Enforce fetching of user id
With the change of commit 3e61bdc431 and
the relase of v3.3.0 users that had their email address used as login
are not able to login anymore. The dav_user should be empty if users
tried to create a account in the meantime. Therefore we fetch the user
id in the case dav_user (and then Account::_davUser) is empty. We then
store the user id in dav_user.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-11 16:43:11 +00:00
Matthieu Gallien
4d7f72e3a1 Merge pull request #3647 from nextcloud/backport/3632/stable-3.3
[stable-3.3] Ensure that the users id is used for accessing webdav
2021-08-11 16:58:39 +02:00
Felix Weilbach
6a414d5fb3 Ensure that the users id is used for accessing webdav
https://docs.nextcloud.com/server/latest/developer_manual/client_apis/LoginFlow/index.html#obtaining-the-login-credentials
states that the email address can be used for login but it's not
allowed to use the email address to access webdav.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-11 14:18:35 +00:00
Nextcloud bot
694c6e7214 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-11 03:53:48 +00:00
Nextcloud bot
e0e4e9778b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-10 04:09:05 +00:00
Nextcloud bot
7baa66b83e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-09 03:53:21 +00:00
Nextcloud bot
301bb2024e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-08 03:48:27 +00:00
Nextcloud bot
f7fce0100b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-07 03:57:06 +00:00
Nextcloud bot
af894485b4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-06 04:01:23 +00:00
Nextcloud bot
2fb609fa98 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-05 03:53:30 +00:00
Nextcloud bot
c4627c3c04 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-04 03:53:10 +00:00
Nextcloud bot
5f0e8b8268 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-03 03:52:44 +00:00
Nextcloud bot
99c6bee64b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-02 03:26:03 +00:00
Nextcloud bot
853bfed89a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-01 03:27:14 +00:00
Nextcloud bot
86dc3fefc8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-31 03:32:43 +00:00
Nextcloud bot
ea800b638d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-30 03:24:19 +00:00
Matthieu Gallien
a2e69d8574 Merge pull request #3610 from nextcloud/backport/3609/stable-3.3
[stable-3.3] Update supported server versions
2021-07-29 12:03:32 +02:00
Felix Weilbach
0178b322f9 Update supported server versions
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-29 10:03:10 +00:00
395 changed files with 13748 additions and 48336 deletions

View File

@@ -12,7 +12,7 @@
BasedOnStyle: WebKit BasedOnStyle: WebKit
Standard: Cpp11 Standard: Cpp11
ColumnLimit: 120 ColumnLimit: 0
# Disable reflow of qdoc comments: indentation rules are different. # Disable reflow of qdoc comments: indentation rules are different.
# Translation comments are also excluded # Translation comments are also excluded
@@ -61,5 +61,3 @@ ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCH
MaxEmptyLinesToKeep: 2 MaxEmptyLinesToKeep: 2
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
SpaceBeforeCpp11BracedList: false
Cpp11BracedListStyle: true

View File

@@ -24,7 +24,7 @@ Checks: '-*,
modernize-use-nodiscard, modernize-use-nodiscard,
modernize-use-equals-default, modernize-use-equals-default,
modernize-use-noexcept, modernize-use-noexcept,
modernize-use-override, modernize-user-override,
modernize-use-nullptr, modernize-use-nullptr,
modernize-use-transparent-functors, modernize-use-transparent-functors,
modernize-use-uncaught-exceptions, modernize-use-uncaught-exceptions,

View File

@@ -1,17 +1,17 @@
kind: pipeline kind: pipeline
name: qt-5.15 name: qt-5.12
steps: steps:
- name: cmake - name: cmake
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
commands: commands:
- cd /drone/build - cd /drone/build
- cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_BUILD_TYPE=Debug -DBUILD_UPDATER=ON -DBUILD_TESTING=1 -DECM_ENABLE_SANITIZERS=address -DCMAKE_CXX_FLAGS=-Werror ../src - cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_BUILD_TYPE=Debug -DBUILD_UPDATER=ON -DBUILD_TESTING=1 -DECM_ENABLE_SANITIZERS=address ../src
- name: compile - name: compile
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
@@ -19,7 +19,7 @@ steps:
- cd /drone/build - cd /drone/build
- make -j$(nproc) - make -j$(nproc)
- name: test - name: test
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
@@ -27,7 +27,7 @@ steps:
- cd /drone/build - cd /drone/build
- useradd -m -s /bin/bash test - useradd -m -s /bin/bash test
- chown -R test:test . - chown -R test:test .
- su -c 'ASAN_OPTIONS=detect_leaks=0 xvfb-run ctest --output-on-failure' test - su -c 'ASAN_OPTIONS=detect_leaks=0 ctest --output-on-failure' test
volumes: volumes:
- name: build - name: build
@@ -43,27 +43,27 @@ trigger:
--- ---
kind: pipeline kind: pipeline
name: qt-5.15-clang name: qt-5.12-clang
steps: steps:
- name: cmake - name: cmake
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
commands: commands:
- cd /drone/build - cd /drone/build
- cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 -DCMAKE_BUILD_TYPE=Debug -DBUILD_UPDATER=ON -DBUILD_TESTING=1 -DECM_ENABLE_SANITIZERS=address -DCMAKE_CXX_FLAGS=-Werror ../src - cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clazy -DCMAKE_BUILD_TYPE=Debug -DBUILD_UPDATER=ON -DBUILD_TESTING=1 -DECM_ENABLE_SANITIZERS=address ../src
- name: compile - name: compile
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
commands: commands:
- cd /drone/build - cd /drone/build
- ninja - ninja 2>1 | /drone/src/admin/linux/count_compiler_warnings.py /drone/src
- name: test - name: test
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
@@ -71,9 +71,9 @@ steps:
- cd /drone/build - cd /drone/build
- useradd -m -s /bin/bash test - useradd -m -s /bin/bash test
- chown -R test:test . - chown -R test:test .
- su -c 'ASAN_OPTIONS=detect_leaks=0 xvfb-run ctest --output-on-failure' test - su -c 'ASAN_OPTIONS=detect_leaks=0 ctest --output-on-failure' test
- name: clang-tidy - name: clang-tidy
image: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4 image: ghcr.io/nextcloud/continuous-integration-client:client-5.12-18
volumes: volumes:
- name: build - name: build
path: /drone/build path: /drone/build
@@ -98,14 +98,14 @@ name: AppImage
steps: steps:
- name: build - name: build
image: ghcr.io/nextcloud/continuous-integration-client-appimage:client-appimage-3 image: ghcr.io/nextcloud/continuous-integration-client-appimage:client-appimage-1
environment: environment:
CI_UPLOAD_GIT_TOKEN: CI_UPLOAD_GIT_TOKEN:
from_secret: CI_UPLOAD_GIT_TOKEN from_secret: CI_UPLOAD_GIT_TOKEN
CI_UPLOAD_GIT_USERNAME: CI_UPLOAD_GIT_USERNAME:
from_secret: CI_UPLOAD_GIT_USERNAME from_secret: CI_UPLOAD_GIT_USERNAME
commands: commands:
- BUILDNR=$DRONE_BUILD_NUMBER VERSION_SUFFIX=$DRONE_PULL_REQUEST BUILD_UPDATER=ON DESKTOP_CLIENT_ROOT=$DRONE_WORKSPACE /bin/bash -c "./admin/linux/build-appimage.sh" - /bin/bash -c "./admin/linux/build-appimage.sh"
- /bin/bash -c "./admin/linux/upload-appimage.sh" || echo "Upload failed, however this is an optional step." - /bin/bash -c "./admin/linux/upload-appimage.sh" || echo "Upload failed, however this is an optional step."
trigger: trigger:
branch: branch:

View File

@@ -3,44 +3,25 @@
# https://github.com/nextcloud/.github # https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: Rebase command
on: on:
issue_comment: issue_comment:
types: created types: [ created ]
name: Automatic Rebase
jobs: jobs:
rebase: rebase:
runs-on: ubuntu-latest name: Rebase
# On pull requests and if the comment starts with `/rebase` # On pull requests and if the comment starts with `/rebase`
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase') if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps: steps:
- name: Add reaction on start
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }}
comment-id: ${{ github.event.comment.id }}
reaction-type: "+1"
- name: Checkout the latest code - name: Checkout the latest code
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
token: ${{ secrets.COMMAND_BOT_PAT }}
- name: Automatic Rebase - name: Automatic Rebase
uses: cirrus-actions/rebase@1.5 uses: cirrus-actions/rebase@1.5
env: env:
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Add reaction on failure
uses: peter-evans/create-or-update-comment@v1
if: failure()
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }}
comment-id: ${{ github.event.comment.id }}
reaction-type: "-1"

View File

@@ -1,50 +0,0 @@
name: SonarCloud analysis
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build
runs-on: ubuntu-latest
container: ghcr.io/nextcloud/continuous-integration-client:client-5.15-4
env:
SONAR_SERVER_URL: "https://sonarcloud.io"
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Restore cache
uses: actions/cache@v2
with:
path: /cache
key: ${{ runner.os }}
- name: Run build-wrapper
run: |
mkdir build
cd build
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 -DBUILD_UPDATER=ON -DBUILD_TESTING=1 -DBUILD_COVERAGE=ON
build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make -j 2
- name: Run tests
run: |
cd build
useradd -m -s /bin/bash test
chown -R test:test .
su -c 'xvfb-run ctest --output-on-failure --output-junit testResult.xml' test
- name: Generate coverage report
run: |
cd build
su -c 'ctest -T Coverage' test
- name: Run sonar-scanner
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
cp sonar-project.properties build
cd build
sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}"

View File

@@ -22,6 +22,5 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[bg_BG]=@APPLICATION_ICON_NAME@ Icon[bg_BG]=@APPLICATION_ICON_NAME@
Name[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране
Comment[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране Comment[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране
GenericName[bg_BG]=Синхронизиране на папка GenericName[bg_BG]=Синхронизиране на папка

View File

@@ -22,6 +22,5 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[en_GB]=@APPLICATION_ICON_NAME@ Icon[en_GB]=@APPLICATION_ICON_NAME@
Name[en_GB]=@APPLICATION_NAME@ Desktop
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
GenericName[en_GB]=Folder Sync GenericName[en_GB]=Folder Sync

View File

@@ -22,6 +22,5 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[ru]=@APPLICATION_ICON_NAME@ Icon[ru]=@APPLICATION_ICON_NAME@
Name[ru]=@APPLICATION_NAME@ Desktop
Comment[ru]=Клиент синхронизации @APPLICATION_NAME@ для ПК Comment[ru]=Клиент синхронизации @APPLICATION_NAME@ для ПК
GenericName[ru]=Синхронизация папок GenericName[ru]=Синхронизация папок

View File

@@ -1,27 +0,0 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ Desktop
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
MimeType=application/vnd.@APPLICATION_EXECUTABLE@;
Actions=Quit;
# Translations
[Desktop Action Quit]
Exec=@APPLICATION_EXECUTABLE@ --quit
Name=Quit @APPLICATION_NAME@
Icon=@APPLICATION_EXECUTABLE@
# Translations
Icon[vi]=@APPLICATION_ICON_NAME@
Name[vi]=@APPLICATION_NAME@ Máy tính
Comment[vi]=Ứng dụng đồng bộ @APPLICATION_NAME@ cho máy tính
GenericName[vi]=Đồng bộ thư mục

View File

@@ -42,13 +42,10 @@ if(NOT CRASHREPORTER_EXECUTABLE)
set(CRASHREPORTER_EXECUTABLE "${APPLICATION_EXECUTABLE}_crash_reporter") set(CRASHREPORTER_EXECUTABLE "${APPLICATION_EXECUTABLE}_crash_reporter")
endif() endif()
include(Warnings) set(synclib_NAME "${APPLICATION_EXECUTABLE}sync")
set(csync_NAME "${APPLICATION_EXECUTABLE}_csync")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") include(Warnings)
add_compile_options(-fdiagnostics-color=always)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options(-fcolor-diagnostics)
endif()
include(${CMAKE_SOURCE_DIR}/VERSION.cmake) include(${CMAKE_SOURCE_DIR}/VERSION.cmake)
# For config.h # For config.h
@@ -77,9 +74,9 @@ include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1) get_git_head_revision(GIT_REFSPEC GIT_SHA1)
add_definitions( add_definitions(
-DQT_DISABLE_DEPRECATED_BEFORE=0x000000
-DQT_USE_QSTRINGBUILDER -DQT_USE_QSTRINGBUILDER
-DQT_MESSAGELOGCONTEXT #enable function name and line number in debug output -DQT_MESSAGELOGCONTEXT #enable function name and line number in debug output
-DQT_DEPRECATED_WARNINGS
) )
# if we cannot get it from git, directly try .tag (packages) # if we cannot get it from git, directly try .tag (packages)
@@ -96,7 +93,11 @@ endif()
message(STATUS "GIT_SHA1 ${GIT_SHA1}") message(STATUS "GIT_SHA1 ${GIT_SHA1}")
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
set(SHAREDIR ${CMAKE_INSTALL_DATADIR}) set(DATADIR ${DATA_INSTALL_DIR})
if(WIN32)
set(DATADIR "share")
endif(WIN32)
set(SHAREDIR ${DATADIR})
##### #####
## handle BUILD_OWNCLOUD_OSX_BUNDLE ## handle BUILD_OWNCLOUD_OSX_BUNDLE

View File

@@ -11,8 +11,6 @@ set( APPLICATION_SERVER_URL "" CACHE STRING "URL for the server to use. If enter
set( APPLICATION_SERVER_URL_ENFORCE ON ) # If set and APPLICATION_SERVER_URL is defined, the server can only connect to the pre-defined URL set( APPLICATION_SERVER_URL_ENFORCE ON ) # If set and APPLICATION_SERVER_URL is defined, the server can only connect to the pre-defined URL
set( APPLICATION_REV_DOMAIN "com.nextcloud.desktopclient" ) set( APPLICATION_REV_DOMAIN "com.nextcloud.desktopclient" )
set( APPLICATION_VIRTUALFILE_SUFFIX "nextcloud" CACHE STRING "Virtual file suffix (not including the .)") set( APPLICATION_VIRTUALFILE_SUFFIX "nextcloud" CACHE STRING "Virtual file suffix (not including the .)")
set( APPLICATION_OCSP_STAPLING_ENABLED OFF )
set( APPLICATION_FORBID_BAD_SSL OFF )
set( LINUX_PACKAGE_SHORTNAME "nextcloud" ) set( LINUX_PACKAGE_SHORTNAME "nextcloud" )
set( LINUX_APPLICATION_ID "${APPLICATION_REV_DOMAIN}.${LINUX_PACKAGE_SHORTNAME}") set( LINUX_APPLICATION_ID "${APPLICATION_REV_DOMAIN}.${LINUX_PACKAGE_SHORTNAME}")
@@ -34,7 +32,6 @@ option( BUILD_UPDATER "Build updater" OFF )
option( WITH_PROVIDERS "Build with providers list" ON ) option( WITH_PROVIDERS "Build with providers list" ON )
option( ENFORCE_VIRTUAL_FILES_SYNC_FOLDER "Enforce use of virtual files sync folder when available" OFF )
## Theming options ## Theming options
set(NEXTCLOUD_BACKGROUND_COLOR "#0082c9" CACHE STRING "Default Nextcloud background color") set(NEXTCLOUD_BACKGROUND_COLOR "#0082c9" CACHE STRING "Default Nextcloud background color")

View File

@@ -1,11 +1,11 @@
set( MIRALL_VERSION_MAJOR 3 ) set( MIRALL_VERSION_MAJOR 3 )
set( MIRALL_VERSION_MINOR 3 ) set( MIRALL_VERSION_MINOR 3 )
set( MIRALL_VERSION_PATCH 81 ) set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_VERSION_YEAR 2021 ) set( MIRALL_VERSION_YEAR 2021 )
set( MIRALL_SOVERSION 0 ) set( MIRALL_SOVERSION 0 )
# Minimum supported server version according to https://docs.nextcloud.com/server/latest/admin_manual/release_schedule.html # Minimum supported server version according to https://docs.nextcloud.com/server/latest/admin_manual/release_schedule.html
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 16) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 20)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MINOR 0) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MINOR 0)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_PATCH 0) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_PATCH 0)

View File

@@ -2,88 +2,78 @@
set -xe set -xe
export APPNAME=${APPNAME:-nextcloud} mkdir /app
export BUILD_UPDATER=${BUILD_UPDATER:-OFF} mkdir /build
export BUILDNR=${BUILDNR:-0000}
export DESKTOP_CLIENT_ROOT=${DESKTOP_CLIENT_ROOT:-/home/user}
#Set Qt-5.15
export QT_BASE_DIR=/opt/qt5.15
#Set Qt-5.12
export QT_BASE_DIR=/opt/qt5.12.10
export QTDIR=$QT_BASE_DIR export QTDIR=$QT_BASE_DIR
export PATH=$QT_BASE_DIR/bin:$PATH export PATH=$QT_BASE_DIR/bin:$PATH
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=$QT_BASE_DIR/lib/pkgconfig:$PKG_CONFIG_PATH export PKG_CONFIG_PATH=$QT_BASE_DIR/lib/pkgconfig:$PKG_CONFIG_PATH
# Set defaults #Set APPID for .desktop file processing
export LINUX_APPLICATION_ID=com.nextcloud.desktopclient.nextcloud
#set defaults
export SUFFIX=${DRONE_PULL_REQUEST:=master} export SUFFIX=${DRONE_PULL_REQUEST:=master}
if [ $SUFFIX != "master" ]; then if [ $SUFFIX != "master" ]; then
SUFFIX="PR-$SUFFIX" SUFFIX="PR-$SUFFIX"
fi fi
if [ "$BUILD_UPDATER" != "OFF" ]; then
BUILD_UPDATER=ON
fi
mkdir /app #QtKeyChain v0.10.0
cd /build
# QtKeyChain
git clone https://github.com/frankosterfeld/qtkeychain.git git clone https://github.com/frankosterfeld/qtkeychain.git
cd qtkeychain cd qtkeychain
git checkout v0.10.0 git checkout v0.10.0
mkdir build mkdir build
cd build cd build
cmake -G Ninja -D CMAKE_INSTALL_PREFIX=/app/usr .. cmake -D CMAKE_INSTALL_PREFIX=/usr ../
cmake --build . --target all make -j4
cmake --build . --target install make install
#Build client
# Build client cd /build
mkdir build-client mkdir build-client
cd build-client cd build-client
cmake \ cmake -D CMAKE_INSTALL_PREFIX=/usr \
-G Ninja \
-D CMAKE_INSTALL_PREFIX=/app/usr \
-D BUILD_TESTING=OFF \ -D BUILD_TESTING=OFF \
-D BUILD_UPDATER=$BUILD_UPDATER \ -D BUILD_UPDATER=ON \
-D MIRALL_VERSION_BUILD=$BUILDNR \ -DMIRALL_VERSION_SUFFIX=PR-$DRONE_PULL_REQUEST \
-D MIRALL_VERSION_SUFFIX="$VERSION_SUFFIX" \ -DMIRALL_VERSION_BUILD=$DRONE_BUILD_NUMBER \
${DESKTOP_CLIENT_ROOT} $DRONE_WORKSPACE
cmake --build . --target all make -j4
cmake --build . --target install make DESTDIR=/app install
# Move stuff around # Move stuff around
cd /app cd /app
mv usr/lib/x86_64-linux-gnu/* usr/lib/ mv ./usr/lib/x86_64-linux-gnu/* ./usr/lib/
rm -rf ./usr/lib/cmake
rm -rf ./usr/include
rm -rf ./usr/mkspecs
rm -rf ./usr/lib/x86_64-linux-gnu/
mkdir usr/plugins # Don't bundle nextcloudcmd as we don't run it anyway
mv usr/lib/${APPNAME}sync_vfs_suffix.so usr/plugins rm -rf ./usr/bin/nextcloudcmd
mv usr/lib/${APPNAME}sync_vfs_xattr.so usr/plugins
rm -rf usr/lib/cmake
rm -rf usr/include
rm -rf usr/mkspecs
rm -rf usr/lib/x86_64-linux-gnu/
# Don't bundle the explorer extentions as we can't do anything with them in the AppImage # Don't bundle the explorer extentions as we can't do anything with them in the AppImage
rm -rf usr/share/caja-python/ rm -rf ./usr/share/caja-python/
rm -rf usr/share/nautilus-python/ rm -rf ./usr/share/nautilus-python/
rm -rf usr/share/nemo-python/ rm -rf ./usr/share/nemo-python/
# Move sync exclude to right location # Move sync exclude to right location
mv usr/etc/*/sync-exclude.lst usr/bin/ mv ./etc/Nextcloud/sync-exclude.lst ./usr/bin/
rm -rf etc rm -rf ./etc
# com.nextcloud.desktopclient.nextcloud.desktop DESKTOP_FILE=/app/usr/share/applications/${LINUX_APPLICATION_ID}.desktop
DESKTOP_FILE=$(ls /app/usr/share/applications/*.desktop)
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' ${DESKTOP_FILE} # Bug in desktop file? sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' ${DESKTOP_FILE} # Bug in desktop file?
cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME
# Because distros need to get their shit together # Because distros need to get their shit together
cp -R /usr/lib/x86_64-linux-gnu/libssl.so* ./usr/lib/ cp -R /lib/x86_64-linux-gnu/libssl.so* ./usr/lib/
cp -R /usr/lib/x86_64-linux-gnu/libcrypto.so* ./usr/lib/ cp -R /lib/x86_64-linux-gnu/libcrypto.so* ./usr/lib/
cp -P /usr/local/lib/libssl.so* ./usr/lib/ cp -P /usr/local/lib/libssl.so* ./usr/lib/
cp -P /usr/local/lib/libcrypto.so* ./usr/lib/ cp -P /usr/local/lib/libcrypto.so* ./usr/lib/
@@ -91,23 +81,19 @@ cp -P /usr/local/lib/libcrypto.so* ./usr/lib/
cp -P -r /usr/lib/x86_64-linux-gnu/nss ./usr/lib/ cp -P -r /usr/lib/x86_64-linux-gnu/nss ./usr/lib/
# Use linuxdeployqt to deploy # Use linuxdeployqt to deploy
wget --ca-directory=/etc/ssl/certs -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" cd /build
wget --ca-directory=/etc/ssl/certs/ -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
chmod a+x linuxdeployqt*.AppImage chmod a+x linuxdeployqt*.AppImage
./linuxdeployqt-continuous-x86_64.AppImage --appimage-extract ./linuxdeployqt-continuous-x86_64.AppImage --appimage-extract
rm ./linuxdeployqt-continuous-x86_64.AppImage rm ./linuxdeployqt-continuous-x86_64.AppImage
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/app/usr/lib/ export LD_LIBRARY_PATH=/app/usr/lib/
./squashfs-root/AppRun ${DESKTOP_FILE} -bundle-non-qt-libs -qmldir=${DESKTOP_CLIENT_ROOT}/src/gui ./squashfs-root/AppRun ${DESKTOP_FILE} -bundle-non-qt-libs -qmldir=$DRONE_WORKSPACE/src/gui
# Set origin # Set origin
./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/lib${APPNAME}sync.so.0 ./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/libnextcloudsync.so.0
# Build AppImage # Build AppImage
./squashfs-root/AppRun ${DESKTOP_FILE} -appimage -updateinformation="gh-releases-zsync|nextcloud-releases|desktop|latest|Nextcloud-*-x86_64.AppImage.zsync" ./squashfs-root/AppRun ${DESKTOP_FILE} -appimage
#move AppImage mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
if [ ! -z "$DRONE_COMMIT" ]
then
mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
fi
mv *.AppImage ${DESKTOP_CLIENT_ROOT}/

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# Small script that counts the warnings which the compiler emits
# and takes care that not more warnings are added.
import sys
import re
import requests
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} REPOSITORY_PATH")
sys.exit(1)
repository_path = sys.argv[1]
warning_regex = re.compile(r'warning:', re.M)
max_allowed_warnings_count_response = requests.get(
"https://nextclouddesktopwarningscount.felixweilbach.de")
if max_allowed_warnings_count_response.status_code != 200:
print('Can not get maximum number of allowed warnings')
sys.exit(1)
max_allowed_warnings_count = int(max_allowed_warnings_count_response.content)
print("Max number of allowed warnings:", max_allowed_warnings_count)
warnings_count = 0
for line in sys.stdin:
if warning_regex.findall(line):
warnings_count += 1
print(line, end="")
if warnings_count > max_allowed_warnings_count:
print("Error: Too many warnings! You probably introduced a new warning!")
sys.exit(1)
print("Total number of warnings:", warnings_count)

View File

@@ -24,7 +24,6 @@ cd /build
# AppImage # AppImage
export APPIMAGE=$(readlink -f ./Nextcloud*.AppImage) export APPIMAGE=$(readlink -f ./Nextcloud*.AppImage)
export UPDATE=$(readlink -f ./Nextcloud*.AppImage.zsync)
export BASENAME=$(basename ${APPIMAGE}) export BASENAME=$(basename ${APPIMAGE})
if ! test -e $APPIMAGE ; then if ! test -e $APPIMAGE ; then
@@ -71,7 +70,6 @@ upload_release_asset()
{ {
uploadUrl=$1 uploadUrl=$1
echo $(curl --max-time 900 -u $GIT_USERNAME:$GIT_TOKEN -X POST $uploadUrl --header "Content-Type: application/octet-stream" --upload-file $APPIMAGE) echo $(curl --max-time 900 -u $GIT_USERNAME:$GIT_TOKEN -X POST $uploadUrl --header "Content-Type: application/octet-stream" --upload-file $APPIMAGE)
echo $(curl --max-time 900 -u $GIT_USERNAME:$GIT_TOKEN -X POST $uploadUrl --header "Content-Type: application/octet-stream" --upload-file $UPDATE)
} }
delete_release_asset() delete_release_asset()
@@ -134,4 +132,4 @@ if [ $TAG_NAME != "master" ]; then
fi fi
echo echo
echo "AppImage link: $browserDownloadUrl" echo "AppImage link: $browserDownloadUrl"

View File

@@ -9,7 +9,7 @@ else()
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0") set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0")
endif() endif()
find_package(Qt5 5.15 COMPONENTS Core REQUIRED) find_package(Qt5 5.12 COMPONENTS Core REQUIRED)
configure_file(create_mac.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh) configure_file(create_mac.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh)
configure_file(macosx.pkgproj.cmake ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj) configure_file(macosx.pkgproj.cmake ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)
configure_file(pre_install.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh) configure_file(pre_install.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh)

View File

@@ -1,82 +0,0 @@
#!/usr/bin/env python
import sys
import os
import subprocess
# A general note: We first produce a x86_64 and a arm64 app package
# and then merge them together instead of compiling the desktop client
# with the CMake option CMAKE_OSX_ARCHITECTURES="x86_64;arm64" because
# macdeployqt can not handle universal binaries well. In the future
# with Qt6 this might change and this script will become obsolete.
def usage(program_name):
print("Creates a universal app package from a x86_64 and a arm64 app package.")
print("Usage: {} x86_64_app_file arm64_app_file output_directory".format(program_name))
print("Example: {} some_dir/Nextcloud.app some_other_dir/Nextcloud.app output_dir".format(program_name))
def execute(command):
return subprocess.check_output(command)
def path_relative_to_package(app_package_file_path, file_path):
if file_path.startswith(app_package_file_path):
relative_path = file_path[len(app_package_file_path):]
if relative_path.startswith("/"):
return relative_path[1:]
return relative_path
return file_path
def is_executable(file_path):
output = str(execute(["file", file_path]))
if (("Mach-O 64-bit dynamically linked shared library" in output)
or ("Mach-O 64-bit executable" in output)):
return True
return False
if __name__ == "__main__":
if len(sys.argv) != 4:
usage(sys.argv[0])
sys.exit(1)
x86_64_app_file = sys.argv[1]
if not os.path.exists(x86_64_app_file):
print("Can't create universal: Path {} already exists".format(x86_64_app_file))
sys.exit(1)
arm64_app_file = sys.argv[2]
if not os.path.exists(arm64_app_file):
print("Can't create universal: Path {} already exists".format(arm64_app_file))
sys.exit(1)
output_dir = sys.argv[3]
# Copy the Arm64 variant to the output location if possible
if not os.path.exists(output_dir):
os.makedirs(output_dir)
app_file_name = os.path.basename(arm64_app_file)
universal_app_file = os.path.join(output_dir, app_file_name)
if os.path.exists(universal_app_file):
print("Can't create universal: Path {} already exists".format(universal_app_file))
sys.exit(1)
execute(["cp", "-a", arm64_app_file, output_dir])
# Now walk through the copied arm64 version and replace the binaries
for root, dirs, files in os.walk(universal_app_file):
for f in files:
absoulte_file_path = os.path.join(root, f)
root_relative = path_relative_to_package(universal_app_file, root)
x86_64_absolute_path = os.path.join(x86_64_app_file, root_relative, f)
arm64_absolute_path = os.path.join(arm64_app_file, root_relative, f)
if os.path.islink(absoulte_file_path) or not is_executable(absoulte_file_path):
continue
try:
execute(["lipo", "-create", "-output", absoulte_file_path, arm64_absolute_path, x86_64_absolute_path])
except:
print("Could not merge {} with {} into {}!".format(arm64_absolute_path, x86_64_absolute_path, absoulte_file_path))
print("Finished :)")

View File

@@ -3,7 +3,7 @@
# Always enable the new 10.10 finder plugin if available # Always enable the new 10.10 finder plugin if available
if [ -x "$(command -v pluginkit)" ]; then if [ -x "$(command -v pluginkit)" ]; then
# add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463 # add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463
pluginkit -a "/Applications/@APPLICATION_NAME@.app/Contents/PlugIns/FinderSyncExt.appex/" pluginkit -a "/Applications/@APPLICATION_EXECUTABLE@.app/Contents/PlugIns/FinderSyncExt.appex/"
# Since El Capitan we need to sleep #4650 # Since El Capitan we need to sleep #4650
sleep 10s sleep 10s
# enable it # enable it

View File

@@ -2,6 +2,5 @@
# kill the old version. see issue #2044 # kill the old version. see issue #2044
killall @APPLICATION_EXECUTABLE@ killall @APPLICATION_EXECUTABLE@
killall @APPLICATION_NAME@
exit 0 exit 0

View File

@@ -32,6 +32,9 @@ install:
build_script: build_script:
- ps: | - ps: |
craft --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client craft --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client
craft --package --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client
cp C:\CraftMaster\windows-msvc2019_64-cl\tmp\*.7z $env:APPVEYOR_BUILD_FOLDER
cp C:\CraftMaster\windows-msvc2019_64-cl\tmp\*.exe $env:APPVEYOR_BUILD_FOLDER
test_script: test_script:
- ps: | - ps: |
@@ -40,3 +43,7 @@ test_script:
environment: environment:
matrix: matrix:
- TARGET: windows-msvc2019_64-cl - TARGET: windows-msvc2019_64-cl
artifacts:
- path: '*.7z'
- path: '*.exe'

View File

@@ -0,0 +1,253 @@
#.rst:
# GNUInstallDirs
# --------------
#
# Define GNU standard installation directories
#
# Provides install directory variables as defined for GNU software:
#
# ::
#
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
#
# Inclusion of this module defines the following variables:
#
# ::
#
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
#
# where <dir> is one of:
#
# ::
#
# BINDIR - user executables (bin)
# SBINDIR - system admin executables (sbin)
# LIBEXECDIR - program executables (libexec)
# SYSCONFDIR - read-only single-machine data (etc)
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
# LOCALSTATEDIR - modifiable single-machine data (var)
# LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
# INCLUDEDIR - C header files (include)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# DATAROOTDIR - read-only architecture-independent data root (share)
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
# INFODIR - info documentation (DATAROOTDIR/info)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# MANDIR - man documentation (DATAROOTDIR/man)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
#
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION
# options of install() commands for the corresponding file type. If the
# includer does not define a value the above-shown default will be used
# and the value will appear in the cache for editing by the user. Each
# CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the
# value of CMAKE_INSTALL_PREFIX.
#=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
# Copyright 2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Installation directories
#
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif()
# We check if the variable was manually set and not cached, in order to
# allow projects to set the values as normal variables before including
# GNUInstallDirs to avoid having the entries cached or user-editable. It
# replaces the "if(NOT DEFINED CMAKE_INSTALL_XXX)" checks in all the
# other cases.
# If CMAKE_INSTALL_LIBDIR is defined, if _libdir_set is false, then the
# variable is a normal one, otherwise it is a cache one.
get_property(_libdir_set CACHE CMAKE_INSTALL_LIBDIR PROPERTY TYPE SET)
if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
AND DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
AND NOT "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" STREQUAL "${CMAKE_INSTALL_PREFIX}"))
# If CMAKE_INSTALL_LIBDIR is not defined, it is always executed.
# Otherwise:
# * if _libdir_set is false it is not executed (meaning that it is
# not a cache variable)
# * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is not defined it is
# not executed
# * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX and
# CMAKE_INSTALL_PREFIX are the same string it is not executed.
# _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is updated after the
# execution, of this part of code, therefore at the next inclusion
# of the file, CMAKE_INSTALL_LIBDIR is defined, and the 2 strings
# are equal, meaning that the if is not executed the code the
# second time.
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling
# - we are NOT on debian
# - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
# and CMAKE_INSTALL_PREFIX is "/usr"
# See http://wiki.debian.org/Multiarch
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
set(__LAST_LIBDIR_DEFAULT "lib")
# __LAST_LIBDIR_DEFAULT is the default value that we compute from
# _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX, not a cache entry for
# the value that was last used as the default.
# This value is used to figure out whether the user changed the
# CMAKE_INSTALL_LIBDIR value manually, or if the value was the
# default one. When CMAKE_INSTALL_PREFIX changes, the value is
# updated to the new default, unless the user explicitly changed it.
endif()
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
AND NOT CMAKE_CROSSCOMPILING)
if (EXISTS "/etc/debian_version") # is this a debian system ?
if(CMAKE_LIBRARY_ARCHITECTURE)
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
set(__LAST_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif()
endif()
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
elseif(DEFINED __LAST_LIBDIR_DEFAULT
AND "${__LAST_LIBDIR_DEFAULT}" STREQUAL "${CMAKE_INSTALL_LIBDIR}")
set_property(CACHE CMAKE_INSTALL_LIBDIR PROPERTY VALUE "${_LIBDIR_DEFAULT}")
endif()
endif()
# Save for next run
set(_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "CMAKE_INSTALL_PREFIX during last run")
unset(_libdir_set)
unset(__LAST_LIBDIR_DEFAULT)
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
endif()
#-----------------------------------------------------------------------------
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
# the cache and store the defaults in local variables if the cache values are
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
endif()
if(NOT CMAKE_INSTALL_INFODIR)
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
endif()
if(NOT CMAKE_INSTALL_LOCALEDIR)
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
endif()
if(NOT CMAKE_INSTALL_MANDIR)
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
endif()
if(NOT CMAKE_INSTALL_DOCDIR)
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
endif()
#-----------------------------------------------------------------------------
mark_as_advanced(
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_SBINDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_SYSCONFDIR
CMAKE_INSTALL_SHAREDSTATEDIR
CMAKE_INSTALL_LOCALSTATEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_DATADIR
CMAKE_INSTALL_INFODIR
CMAKE_INSTALL_LOCALEDIR
CMAKE_INSTALL_MANDIR
CMAKE_INSTALL_DOCDIR
)
# Result directories
#
foreach(dir
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
else()
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
endif()
endforeach()

View File

@@ -27,4 +27,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
endif() endif()
if(DEFINED MIRALL_FATAL_WARNINGS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif(DEFINED MIRALL_FATAL_WARNINGS)
endif() endif()

View File

@@ -29,10 +29,7 @@
#cmakedefine APPLICATION_WIZARD_HEADER_TITLE_COLOR "@APPLICATION_WIZARD_HEADER_TITLE_COLOR@" #cmakedefine APPLICATION_WIZARD_HEADER_TITLE_COLOR "@APPLICATION_WIZARD_HEADER_TITLE_COLOR@"
#cmakedefine APPLICATION_WIZARD_USE_CUSTOM_LOGO "@APPLICATION_WIZARD_USE_CUSTOM_LOGO@" #cmakedefine APPLICATION_WIZARD_USE_CUSTOM_LOGO "@APPLICATION_WIZARD_USE_CUSTOM_LOGO@"
#cmakedefine APPLICATION_VIRTUALFILE_SUFFIX "@APPLICATION_VIRTUALFILE_SUFFIX@" #cmakedefine APPLICATION_VIRTUALFILE_SUFFIX "@APPLICATION_VIRTUALFILE_SUFFIX@"
#cmakedefine APPLICATION_OCSP_STAPLING_ENABLED "@APPLICATION_OCSP_STAPLING_ENABLED@"
#cmakedefine APPLICATION_FORBID_BAD_SSL "@APPLICATION_FORBID_BAD_SSL@"
#define APPLICATION_DOTVIRTUALFILE_SUFFIX "." APPLICATION_VIRTUALFILE_SUFFIX #define APPLICATION_DOTVIRTUALFILE_SUFFIX "." APPLICATION_VIRTUALFILE_SUFFIX
#cmakedefine01 ENFORCE_VIRTUAL_FILES_SYNC_FOLDER
#cmakedefine ZLIB_FOUND @ZLIB_FOUND@ #cmakedefine ZLIB_FOUND @ZLIB_FOUND@

View File

@@ -406,7 +406,7 @@ Virtual Files
------------- -------------
.. note:: .. note::
* This feature is currently only available on ``Windows`` by default. ``Linux`` and ``macOS`` implementations are experimental and must be enabled by adding ``showExperimentalOptions=true`` to the ``nextcloud.cfg`` configuration file in the ``App Data`` folder. * This feature is currently only available on ``Windows`` by default. ``Linux`` implementation is experimental and must be enabled by adding ``showExperimentalOptions=true`` to the ``nextcloud.cfg`` configuration file in the ``App Data`` folder. ``macOS``, at the moment, is using the same backend as ``Linux`` one. It can be enabled with the same ``showExperimentalOptions`` flag.
Oftentimes, users are working with a huge amount of files that are big in size. Synchronizing every such file to a device that's running a Nextcloud desktop client is not always possible due to the user's device storage space limitation. Oftentimes, users are working with a huge amount of files that are big in size. Synchronizing every such file to a device that's running a Nextcloud desktop client is not always possible due to the user's device storage space limitation.
Let's assume that your desktop client is connected to a server that has 1TB of data. You want all those files at hand, so you can quickly access any file via the file explorer. Your device has 512GB local storage device. Let's assume that your desktop client is connected to a server that has 1TB of data. You want all those files at hand, so you can quickly access any file via the file explorer. Your device has 512GB local storage device.
@@ -416,15 +416,8 @@ Needless to say, this is far from being convenient.
That's why, starting from 3.2.0, we are introducing the VFS (Virtual Files) feature. You may have had experience working with a similar feature in other cloud sync clients. This feature is known by different names: Files On-Demand, SmartSync, etc. That's why, starting from 3.2.0, we are introducing the VFS (Virtual Files) feature. You may have had experience working with a similar feature in other cloud sync clients. This feature is known by different names: Files On-Demand, SmartSync, etc.
The VFS does not occupy much space on the user's storage. It just creates placeholders for each file and folder. These files are quite small and only contain metadata needed to display them properly and to fetch the actual file when needed. The VFS does not occupy much space on the user's storage. It just creates placeholders for each file and folder. These files are quite small and only contain metadata needed to display them properly and to fetch the actual file when needed.
When one tries to open a file, for example by double clicking on a One will see a hydration (in other words - file download) process when double-clicking on a file that must become available. There will be a progress-bar popup displayed if the file is large enough. So, the hydration process can be observed and it makes it easy to then find out, how long, it would take to fetch the actual file from the server.
file in the Windows Explorer, one will see that the file gets The "Hydration" can be thought of as "downloading" or "fetching" the file contents. As soon as hydration is complete, the file will then be opened normally as now it is a real file on the user's storage. It won't disappear, and, from now on, will always be available, unless it is manually dehydrated.
downloaded and becomes available locally. This can be observed by a
small progress-bar popup if the file is large enough.
As soon as the download is complete, the file will then be opened
normally as now it is a real file on the user's storage. It won't
disappear, and, from now on, will always be available, unless it is
manually dehydrated.
.. image:: images/vfs_hydration_progress_bar.png .. image:: images/vfs_hydration_progress_bar.png
:alt: VFS hydration progress bar :alt: VFS hydration progress bar

View File

@@ -32,9 +32,10 @@ itself. Should the silent update fail, the client offers a manual download.
macOS macOS
^^^^^ ^^^^^
There is no automatic updater on macOS. If a new update is available, If a new update is available, the Nextcloud client initializes a pop-up dialog
the Nextcloud client initializes a pop-up dialog to alert you of the to alert you of the update and requesting that you update to the latest
update and requesting that you update to the latest version manually. version. Due to their use of the Sparkle frameworks, this is the default
process for macOS applications.
Linux Linux
^^^^^ ^^^^^
@@ -95,6 +96,14 @@ To prevent automatic updates and disallow manual overrides:
.. note:: branded clients have different key names .. note:: branded clients have different key names
Preventing Automatic Updates in macOS Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can disable the automatic update mechanism, in the macOS operating system,
by copying the file
``nextcloud.app/Contents/Resources/deny_autoupdate_com.nextcloud.desktopclient.plist``
to ``/Library/Preferences/com.nextcloud.desktopclient.plist``.
Preventing Automatic Updates in Linux Environments Preventing Automatic Updates in Linux Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -50,7 +50,7 @@ copyright = u'2013-2021, The Nextcloud developers'
# The short X.Y version. # The short X.Y version.
version = '3.3' version = '3.3'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '3.3.81' release = '3.3.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@@ -41,7 +41,7 @@ Some interesting values that can be set on the configuration file are:
| ``chunkSize`` | ``10000000`` (10 MB) | Specifies the chunk size of uploaded files in bytes. | | ``chunkSize`` | ``10000000`` (10 MB) | Specifies the chunk size of uploaded files in bytes. |
| | | The client will dynamically adjust this size within the maximum and minimum bounds (see below). | | | | The client will dynamically adjust this size within the maximum and minimum bounds (see below). |
+----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+ +----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
| ``maxChunkSize`` | ``1000000000`` (1000 MB) | Specifies the maximum chunk size of uploaded files in bytes. | | ``maxChunkSize`` | ``100000000`` (100 MB) | Specifies the maximum chunk size of uploaded files in bytes. |
+----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+ +----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
| ``minChunkSize`` | ``1000000`` (1 MB) | Specifies the minimum chunk size of uploaded files in bytes. | | ``minChunkSize`` | ``1000000`` (1 MB) | Specifies the minimum chunk size of uploaded files in bytes. |
+----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+ +----------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -157,35 +157,6 @@ icon.
If a directory includes ignored files that are marked with warning icons If a directory includes ignored files that are marked with warning icons
that does not change the status of the parent directories. that does not change the status of the parent directories.
Set the user status
-------------------
If you have the user status app installed on your Nextcloud server,
you can set your user status from the desktop client. To do so, open
the main dialog. Then click on your avatar and then click on the three
dots. In the menu that opens click on **Set status**.
.. figure:: images/user_status_selector_main_dialog.png
:alt: Open user status dialog from main dialog.
In the dialog that opens, you can set your online status if
you click on either **Online**, **Away**, **Do not disturb** or
**Invisible**. You can also set a custom status message with the text
field below or choose one of the predefined status messages below. It
is also possible to set a custom emoji if you click on the button with
the emoji beside the text input field. The last thing you might want
to set is when your user status should be cleared. You can choose the
period after which the user status will be cleared by clicking on the
button on the left hand side of the text **Clear status message after**.
.. figure:: images/user_status-selector_dialog.png
:alt: Dialog to set user status.
If you are happy with the status you have created you can enable this
status with the button **Set status message**. If you had already a
status set, you can clear the status by clicking the cutton **Clear
status message**.
Sharing From Your Desktop Sharing From Your Desktop
------------------------- -------------------------

View File

@@ -46,9 +46,6 @@ the server URL.
Other command line switches supported by ``nextcloudcmd`` include the following: Other command line switches supported by ``nextcloudcmd`` include the following:
``--path``
Overrides default remote root folder to a specific subfolder on the server(e.g.: /Documents would sync the Documents subfolder on the server)
``--user``, ``-u`` ``[user]`` ``--user``, ``-u`` ``[user]``
Use ``user`` as the login name. Use ``user`` as the login name.
@@ -70,6 +67,12 @@ Other command line switches supported by ``nextcloudcmd`` include the following:
``--httpproxy http://[user@pass:]<server>:<port>`` ``--httpproxy http://[user@pass:]<server>:<port>``
Uses ``server`` as HTTP proxy. Uses ``server`` as HTTP proxy.
``--nonshib``
Uses Non Shibboleth WebDAV Authentication
``--davpath [path]``
Overrides the WebDAV Path with ``path``
``--exclude [file]`` ``--exclude [file]``
Exclude list file Exclude list file
@@ -89,15 +92,15 @@ Credential Handling
:: ::
$ nextcloudcmd /home/user/my_sync_folder https://carla:secret@server/nextcloud $ nextcloudcmd /home/user/my_sync_folder https://carla:secret@server/nextcloud/remote.php/dav/
To synchronize the Nextcloud directory ``Music`` to the local directory To synchronize the Nextcloud directory ``Music`` to the local directory
``media/music``, through a proxy listening on port ``8080``, and on a gateway ``media/music``, through a proxy listening on port ``8080``, and on a gateway
machine using IP address ``192.168.178.1``, the command line would be:: machine using IP address ``192.168.178.1``, the command line would be::
$ nextcloudcmd --httpproxy http://192.168.178.1:8080 --path /Music \ $ nextcloudcmd --httpproxy http://192.168.178.1:8080 \
$HOME/media/music \ $HOME/media/music \
https://server/nextcloud https://server/nextcloud/remote.php/dav/Music
``nextcloudcmd`` will prompt for the user name and password, unless they have ``nextcloudcmd`` will prompt for the user name and password, unless they have
been specified on the command line or ``-n`` has been passed. been specified on the command line or ``-n`` has been passed.
@@ -117,5 +120,5 @@ Example
:: ::
$ nextcloudcmd --path /<Directory_that_has_been_created> /home/user/<my_sync_folder> \ $ nextcloudcmd /home/user/<my_sync_folder> \
https://<username>:<secret>@<server_address> https://<username>:<secret>@<server_address>/remote.php/dav/<Directory_that_has_been_created>

View File

@@ -24,14 +24,11 @@ The first parameter is the local directory. The second parameter is
the server URL. the server URL.
.. note:: Prior to the 1.6 release of nextcloudcmd, the tool only accepted .. note:: Prior to the 1.6 release of nextcloudcmd, the tool only accepted
``owncloud://`` or ``ownclouds://`` in place of ``http://`` and ``https://`` as ``nextcloud://`` or ``nextclouds://`` in place of ``http://`` and ``https://`` as
a scheme. See ``Examples`` for details. a scheme. See ``Examples`` for details.
OPTIONS OPTIONS
======= =======
``--path``
Overrides default remote root folder to a specific subfolder on the server(e.g.: /Documents would sync the Documents subfolder on the server)
``—user``, ``-u`` ``[user]`` ``—user``, ``-u`` ``[user]``
Use ``user`` as the login name. Use ``user`` as the login name.
@@ -53,6 +50,12 @@ OPTIONS
``—httpproxy http://[user@pass:]<server>:<port>`` ``—httpproxy http://[user@pass:]<server>:<port>``
Uses ``server`` as HTTP proxy. Uses ``server`` as HTTP proxy.
``—nonshib``
Uses Non Shibboleth WebDAV Authentication
``—davpath [path]``
Overrides the WebDAV Path with ``path``
``—exclude [file]`` ``—exclude [file]``
Exclude list file Exclude list file
@@ -71,18 +74,18 @@ To synchronize the nextCloud directory ``Music`` to the local directory ``media/
through a proxy listening on port ``8080`` on the gateway machine ``192.168.178.1``, through a proxy listening on port ``8080`` on the gateway machine ``192.168.178.1``,
the command line would be:: the command line would be::
$ nextcloudcmd —httpproxy http://192.168.178.1:8080 --path /Music \ $ nextcloudcmd —httpproxy http://192.168.178.1:8080 \
$HOME/media/music \ $HOME/media/music \
https://server/nextcloud https://server/nextcloud/remote.php/dav/Music
``nextcloudcmd`` will enquire user name and password, unless they have ``nextcloudcmd`` will enquire user name and password, unless they have
been specified on the command line or ``-n`` (see `netrc(5)`) has been passed. been specified on the command line or ``-n`` (see `netrc(5)`) has been passed.
Using the legacy scheme, it would be:: Using the legacy scheme, it would be::
$ nextcloudcmd —httpproxy http://192.168.178.1:8080 --path /Music \ $ nextcloudcmd —httpproxy http://192.168.178.1:8080 \
$HOME/media/music \ $HOME/media/music \
ownclouds://server/nextcloud nextclouds://server/nextcloud/remote.php/dav/Music
BUGS BUGS

View File

@@ -1,27 +1,11 @@
<RCC> <RCC>
<qresource prefix="/qml"> <qresource prefix="/qml">
<file>src/gui/UserStatusSelector.qml</file>
<file>src/gui/UserStatusSelectorDialog.qml</file>
<file>src/gui/EmojiPicker.qml</file>
<file>src/gui/ErrorBox.qml</file>
<file>src/gui/tray/Window.qml</file> <file>src/gui/tray/Window.qml</file>
<file>src/gui/tray/UserLine.qml</file> <file>src/gui/tray/UserLine.qml</file>
<file>src/gui/tray/HeaderButton.qml</file> <file>src/gui/tray/HeaderButton.qml</file>
<file>src/gui/tray/SyncStatus.qml</file>
<file>theme/Style/Style.qml</file> <file>theme/Style/Style.qml</file>
<file>theme/Style/qmldir</file> <file>theme/Style/qmldir</file>
<file>src/gui/tray/ActivityActionButton.qml</file> <file>src/gui/tray/ActivityActionButton.qml</file>
<file>src/gui/tray/ActivityItem.qml</file> <file>src/gui/tray/ActivityItem.qml</file>
<file>src/gui/tray/AutoSizingMenu.qml</file>
<file>src/gui/tray/ActivityList.qml</file>
<file>src/gui/tray/FileActivityDialog.qml</file>
<file>src/gui/tray/UnifiedSearchInputContainer.qml</file>
<file>src/gui/tray/UnifiedSearchResultFetchMoreTrigger.qml</file>
<file>src/gui/tray/UnifiedSearchResultItem.qml</file>
<file>src/gui/tray/UnifiedSearchResultItemSkeleton.qml</file>
<file>src/gui/tray/UnifiedSearchResultItemSkeletonContainer.qml</file>
<file>src/gui/tray/UnifiedSearchResultListItem.qml</file>
<file>src/gui/tray/UnifiedSearchResultNothingFound.qml</file>
<file>src/gui/tray/UnifiedSearchResultSectionItem.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -14,7 +14,7 @@ add_custom_target( mac_overlayplugin ALL
"OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}" "OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
COMMENT building Mac Overlay icons COMMENT building Mac Overlay icons
VERBATIM) VERBATIM)
add_dependencies(mac_overlayplugin nextcloud) # for the ownCloud.icns to be generated add_dependencies(mac_overlayplugin ${APPLICATION_EXECUTABLE}) # for the ownCloud.icns to be generated
INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Release/FinderSyncExt.appex INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Release/FinderSyncExt.appex
DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns

View File

@@ -2,7 +2,7 @@ project(dolphin-owncloud)
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
set(QT_MIN_VERSION "5.15.0") set(QT_MIN_VERSION "5.12.0")
set(KF5_MIN_VERSION "5.16.0") set(KF5_MIN_VERSION "5.16.0")
set(KDE_INSTALL_USE_QT_SYS_PATHS ON CACHE BOOL "Install the plugin in the right directory") set(KDE_INSTALL_USE_QT_SYS_PATHS ON CACHE BOOL "Install the plugin in the right directory")

View File

@@ -37,7 +37,7 @@ public:
explicit OwncloudDolphinPluginAction(QObject* parent, const QList<QVariant>&) explicit OwncloudDolphinPluginAction(QObject* parent, const QList<QVariant>&)
: KAbstractFileItemActionPlugin(parent) { } : KAbstractFileItemActionPlugin(parent) { }
QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) override QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) Q_DECL_OVERRIDE
{ {
auto helper = OwncloudDolphinPluginHelper::instance(); auto helper = OwncloudDolphinPluginHelper::instance();
if (!helper->isConnected() || !fileItemInfos.isLocal()) if (!helper->isConnected() || !fileItemInfos.isLocal())

View File

@@ -1,6 +1,6 @@
if( UNIX AND NOT APPLE ) if( UNIX AND NOT APPLE )
SET(ICON_DIR ${CMAKE_INSTALL_DATADIR}/icons/hicolor) SET(ICON_DIR ${DATADIR}/icons/hicolor)
FOREACH(size 128x128 16x16 256x256 32x32 48x48 64x64 72x72) FOREACH(size 128x128 16x16 256x256 32x32 48x48 64x64 72x72)
file(GLOB files "${size}/*.png") file(GLOB files "${size}/*.png")

View File

@@ -41,7 +41,7 @@ macro(libcloudproviders_add_config _sources)
endmacro(libcloudproviders_add_config _sources) endmacro(libcloudproviders_add_config _sources)
find_package(Qt5 5.15 COMPONENTS DBus) find_package(Qt5 5.12 COMPONENTS DBus)
IF (Qt5DBus_FOUND) IF (Qt5DBus_FOUND)
STRING(TOLOWER "${APPLICATION_VENDOR}" DBUS_VENDOR) STRING(TOLOWER "${APPLICATION_VENDOR}" DBUS_VENDOR)
STRING(REGEX REPLACE "[^A-z0-9]" "" DBUS_VENDOR "${DBUS_VENDOR}") STRING(REGEX REPLACE "[^A-z0-9]" "" DBUS_VENDOR "${DBUS_VENDOR}")

View File

@@ -25,9 +25,9 @@ if( UNIX AND NOT APPLE )
ERROR_VARIABLE errors OUTPUT_VARIABLE out) ERROR_VARIABLE errors OUTPUT_VARIABLE out)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate.py DESTINATION ${CMAKE_INSTALL_DATADIR}/nautilus-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate.py DESTINATION ${DATADIR}/nautilus-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_nemo.py DESTINATION ${CMAKE_INSTALL_DATADIR}/nemo-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_nemo.py DESTINATION ${DATADIR}/nemo-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_caja.py DESTINATION ${CMAKE_INSTALL_DATADIR}/caja-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_caja.py DESTINATION ${DATADIR}/caja-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)

View File

@@ -26,7 +26,7 @@
#pragma once #pragma once
class RemotePathChecker { class __declspec(dllexport) RemotePathChecker {
public: public:
enum FileState { enum FileState {
// Order synced with NCOverlay // Order synced with NCOverlay

View File

@@ -63,7 +63,6 @@
<File Id="NCContextMenu.dll" KeyPath="yes" Source="$(var.HarvestAppDir)\shellext\NCContextMenu.dll"> <File Id="NCContextMenu.dll" KeyPath="yes" Source="$(var.HarvestAppDir)\shellext\NCContextMenu.dll">
<Class Id="$(var.ContextMenuGuid)" Context="InprocServer32" Description="$(var.ContextMenuDescription)" ThreadingModel="apartment" /> <Class Id="$(var.ContextMenuGuid)" Context="InprocServer32" Description="$(var.ContextMenuDescription)" ThreadingModel="apartment" />
</File> </File>
<RegistryValue Root="HKCR" Key="CLSID\$(var.ContextMenuGuid)" Name="ContextMenuOptIn" Value="" Type="string" Action="write" />
<RegistryValue Root="HKCR" Key="AllFileSystemObjects\shellex\ContextMenuHandlers\$(var.ContextMenuRegKeyName)" Value="$(var.ContextMenuGuid)" Type="string" Action="write" /> <RegistryValue Root="HKCR" Key="AllFileSystemObjects\shellex\ContextMenuHandlers\$(var.ContextMenuRegKeyName)" Value="$(var.ContextMenuGuid)" Type="string" Action="write" />
</Component> </Component>

View File

@@ -1,12 +0,0 @@
sonar.projectKey=nextcloud_desktop
sonar.organization=nextcloud
sonar.projectBaseDir=..
sonar.sources=src
sonar.exclusions=3rdparty/**
sonar.language=c++
sonar.cfamily.cache.enabled=false
sonar.sourceEncoding=UTF-8
sonar.cfamily.threads=2
sonar.cfamily.gcov.reportsPath=build/Testing/CoverageInfo
sonar.cfamily.cache.enabled=true,
sonar.cfamily.cache.path=/cache/sonarcloud

View File

@@ -67,8 +67,8 @@ public:
*/ */
const QColor & color() const { return m_color; } const QColor & color() const { return m_color; }
QSize sizeHint() const override; virtual QSize sizeHint() const;
int heightForWidth(int w) const override; int heightForWidth(int w) const;
public slots: public slots:
/*! Starts the spin animation. /*! Starts the spin animation.
\sa stopAnimation isAnimated \sa stopAnimation isAnimated
@@ -98,8 +98,8 @@ public slots:
*/ */
void setColor(const QColor & color); void setColor(const QColor & color);
protected: protected:
void timerEvent(QTimerEvent * event) override; virtual void timerEvent(QTimerEvent * event);
void paintEvent(QPaintEvent * event) override; virtual void paintEvent(QPaintEvent * event);
private: private:
int m_angle = 0; int m_angle = 0;
int m_timerId = -1; int m_timerId = -1;

View File

@@ -57,7 +57,7 @@ public:
QtLockedFile(); QtLockedFile();
QtLockedFile(const QString &name); QtLockedFile(const QString &name);
~QtLockedFile() override; ~QtLockedFile();
bool lock(LockMode mode, bool block = true); bool lock(LockMode mode, bool block = true);
bool unlock(); bool unlock();

View File

@@ -44,13 +44,13 @@ class QtSingleApplication : public QApplication
public: public:
QtSingleApplication(const QString &id, int &argc, char **argv); QtSingleApplication(const QString &id, int &argc, char **argv);
~QtSingleApplication() override; ~QtSingleApplication();
bool isRunning(qint64 pid = -1); bool isRunning(qint64 pid = -1);
void setActivationWindow(QWidget* aw, bool activateOnMessage = true); void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const; QWidget* activationWindow() const;
bool event(QEvent *event) override; bool event(QEvent *event) Q_DECL_OVERRIDE;
QString applicationId() const; QString applicationId() const;
void setBlock(bool value); void setBlock(bool value);

View File

@@ -4,8 +4,10 @@ endif()
include(ECMEnableSanitizers) include(ECMEnableSanitizers)
find_package(Qt5 5.15 COMPONENTS Core Network Xml Concurrent REQUIRED) set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
find_package(Qt5 5.15 COMPONENTS WebEngineWidgets WebEngine)
find_package(Qt5 5.12 COMPONENTS Core Network Xml Concurrent REQUIRED)
find_package(Qt5 5.12 COMPONENTS WebEngineWidgets WebEngine)
if(Qt5WebEngine_FOUND AND Qt5WebEngineWidgets_FOUND) if(Qt5WebEngine_FOUND AND Qt5WebEngineWidgets_FOUND)
add_compile_definitions(WITH_WEBENGINE=1) add_compile_definitions(WITH_WEBENGINE=1)
@@ -59,6 +61,10 @@ elseif(UNIX AND NOT APPLE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
endif() endif()
include_directories(
${CMAKE_SOURCE_DIR}/src/3rdparty
)
set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/theme CACHE STRING "" FORCE) set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/theme CACHE STRING "" FORCE)
add_subdirectory(csync) add_subdirectory(csync)

View File

@@ -1,11 +1,14 @@
project(cmd) project(cmd)
set(CMAKE_AUTOMOC TRUE) set(CMAKE_AUTOMOC TRUE)
set(cmd_NAME ${APPLICATION_EXECUTABLE}cmd)
add_library(cmdCore STATIC simplesslerrorhandler.cpp netrcparser.cpp) add_library(cmdCore STATIC simplesslerrorhandler.cpp netrcparser.cpp)
target_link_libraries(cmdCore target_link_libraries(cmdCore
PUBLIC PUBLIC
Nextcloud::sync "${csync_NAME}"
"${synclib_NAME}"
Qt5::Core Qt5::Core
Qt5::Network Qt5::Network
) )
@@ -24,22 +27,20 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
endif() endif()
if(NOT BUILD_LIBRARIES_ONLY) if(NOT BUILD_LIBRARIES_ONLY)
add_executable(nextcloudcmd cmd.cpp) add_executable(${cmd_NAME} cmd.cpp)
set_target_properties(nextcloudcmd PROPERTIES
RUNTIME_OUTPUT_NAME "${APPLICATION_EXECUTABLE}cmd")
target_link_libraries(nextcloudcmd cmdCore)
if(BUILD_OWNCLOUD_OSX_BUNDLE) if(BUILD_OWNCLOUD_OSX_BUNDLE)
set_target_properties(nextcloudcmd PROPERTIES set_target_properties(${cmd_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${BIN_OUTPUT_DIRECTORY}/${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS") RUNTIME_OUTPUT_DIRECTORY "${BIN_OUTPUT_DIRECTORY}/${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS")
else() else()
set_target_properties(nextcloudcmd PROPERTIES set_target_properties(${cmd_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}) RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY})
install(TARGETS nextcloudcmd install(TARGETS ${cmd_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif() endif()
target_link_libraries(${cmd_NAME} cmdCore)
endif() endif()

View File

@@ -66,7 +66,6 @@ struct CmdOptions
{ {
QString source_dir; QString source_dir;
QString target_url; QString target_url;
QString remotePath = QStringLiteral("/");
QString config_directory; QString config_directory;
QString user; QString user;
QString password; QString password;
@@ -78,6 +77,7 @@ struct CmdOptions
bool ignoreHiddenFiles; bool ignoreHiddenFiles;
QString exclude; QString exclude;
QString unsyncedfolders; QString unsyncedfolders;
QString davPath;
int restartTimes; int restartTimes;
int downlimit; int downlimit;
int uplimit; int uplimit;
@@ -142,7 +142,7 @@ public:
{ {
} }
void askFromUser() override void askFromUser() Q_DECL_OVERRIDE
{ {
_password = ::queryPassword(user()); _password = ::queryPassword(user());
_ready = true; _ready = true;
@@ -155,7 +155,7 @@ public:
_sslTrusted = isTrusted; _sslTrusted = isTrusted;
} }
bool sslIsTrusted() override bool sslIsTrusted() Q_DECL_OVERRIDE
{ {
return _sslTrusted; return _sslTrusted;
} }
@@ -193,7 +193,6 @@ void help()
std::cout << " -h Sync hidden files, do not ignore them" << std::endl; std::cout << " -h Sync hidden files, do not ignore them" << std::endl;
std::cout << " --version, -v Display version and exit" << std::endl; std::cout << " --version, -v Display version and exit" << std::endl;
std::cout << " --logdebug More verbose logging" << std::endl; std::cout << " --logdebug More verbose logging" << std::endl;
std::cout << " --path Path to a folder on a remote server" << std::endl;
std::cout << "" << std::endl; std::cout << "" << std::endl;
exit(0); exit(0);
} }
@@ -270,10 +269,7 @@ void parseOptions(const QStringList &app_args, CmdOptions *options)
} else if (option == "--logdebug") { } else if (option == "--logdebug") {
Logger::instance()->setLogFile("-"); Logger::instance()->setLogFile("-");
Logger::instance()->setLogDebug(true); Logger::instance()->setLogDebug(true);
} else if (option == "--path" && !it.peekNext().startsWith("-")) { } else {
options->remotePath = it.next();
}
else {
help(); help();
} }
} }
@@ -295,10 +291,9 @@ void selectiveSyncFixup(OCC::SyncJournalDb *journal, const QStringList &newList)
bool ok = false; bool ok = false;
const auto selectiveSyncList = journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok); auto oldBlackListSet = journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok).toSet();
const QSet<QString> oldBlackListSet(selectiveSyncList.begin(), selectiveSyncList.end());
if (ok) { if (ok) {
const QSet<QString> blackListSet(newList.begin(), newList.end()); auto blackListSet = newList.toSet();
const auto changes = (oldBlackListSet - blackListSet) + (blackListSet - oldBlackListSet); const auto changes = (oldBlackListSet - blackListSet) + (blackListSet - oldBlackListSet);
for (const auto &it : changes) { for (const auto &it : changes) {
journal->schedulePathForRemoteDiscovery(it); journal->schedulePathForRemoteDiscovery(it);
@@ -310,9 +305,6 @@ void selectiveSyncFixup(OCC::SyncJournalDb *journal, const QStringList &newList)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#ifdef Q_OS_WIN
SetDllDirectory(L"");
#endif
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@@ -321,6 +313,8 @@ int main(int argc, char **argv)
qputenv("OPENSSL_CONF", opensslConf.toLocal8Bit()); qputenv("OPENSSL_CONF", opensslConf.toLocal8Bit());
#endif #endif
qsrand(std::random_device()());
CmdOptions options; CmdOptions options;
options.silent = false; options.silent = false;
options.trustSSL = false; options.trustSSL = false;
@@ -345,15 +339,16 @@ int main(int argc, char **argv)
qFatal("Could not initialize account!"); qFatal("Could not initialize account!");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// check if the webDAV path was added to the url and append if not.
if (options.target_url.contains("/webdav", Qt::CaseInsensitive) || options.target_url.contains("/dav", Qt::CaseInsensitive)) { if (!options.target_url.endsWith("/")) {
qWarning("Dav or webdav in server URL."); options.target_url.append("/");
std::cerr << "Error! Please specify only the base URL of your host with username and password. Example:" << std::endl
<< "http(s)://username:password@cloud.example.com" << std::endl;
return EXIT_FAILURE;
} }
QUrl hostUrl = QUrl::fromUserInput((options.target_url.endsWith(QLatin1Char('/')) || options.target_url.endsWith(QLatin1Char('\\'))) ? options.target_url.chopped(1) : options.target_url); if (!options.target_url.contains(account->davPath())) {
options.target_url.append(account->davPath());
}
QUrl url = QUrl::fromUserInput(options.target_url);
// Order of retrieval attempt (later attempts override earlier ones): // Order of retrieval attempt (later attempts override earlier ones):
// 1. From URL // 1. From URL
@@ -361,8 +356,8 @@ int main(int argc, char **argv)
// 3. From netrc (if enabled) // 3. From netrc (if enabled)
// 4. From prompt (if interactive) // 4. From prompt (if interactive)
QString user = hostUrl.userName(); QString user = url.userName();
QString password = hostUrl.password(); QString password = url.password();
if (!options.user.isEmpty()) { if (!options.user.isEmpty()) {
user = options.user; user = options.user;
@@ -375,7 +370,7 @@ int main(int argc, char **argv)
if (options.useNetrc) { if (options.useNetrc) {
NetrcParser parser; NetrcParser parser;
if (parser.parse()) { if (parser.parse()) {
NetrcParser::LoginPair pair = parser.find(hostUrl.host()); NetrcParser::LoginPair pair = parser.find(url.host());
user = pair.first; user = pair.first;
password = pair.second; password = pair.second;
} }
@@ -393,15 +388,24 @@ int main(int argc, char **argv)
} }
} }
// take the unmodified url to pass to csync_create()
QByteArray remUrl = options.target_url.toUtf8();
// Find the folder and the original owncloud url // Find the folder and the original owncloud url
QStringList splitted = url.path().split("/" + account->davPath());
url.setPath(splitted.value(0));
hostUrl.setScheme(hostUrl.scheme().replace("owncloud", "http")); url.setScheme(url.scheme().replace("owncloud", "http"));
QUrl credentialFreeUrl = hostUrl; QUrl credentialFreeUrl = url;
credentialFreeUrl.setUserName(QString()); credentialFreeUrl.setUserName(QString());
credentialFreeUrl.setPassword(QString()); credentialFreeUrl.setPassword(QString());
const QString folder = options.remotePath; // Remote folders typically start with a / and don't end with one
QString folder = "/" + splitted.value(1);
if (folder.endsWith("/") && folder != "/") {
folder.chop(1);
}
if (!options.proxy.isNull()) { if (!options.proxy.isNull()) {
QString host; QString host;
@@ -438,7 +442,7 @@ int main(int argc, char **argv)
} }
#endif #endif
account->setUrl(hostUrl); account->setUrl(url);
account->setSslErrorHandler(sslErrorHandler); account->setSslErrorHandler(sslErrorHandler);
QEventLoop loop; QEventLoop loop;
@@ -483,7 +487,7 @@ restart_sync:
qCritical() << "Could not open file containing the list of unsynced folders: " << options.unsyncedfolders; qCritical() << "Could not open file containing the list of unsynced folders: " << options.unsyncedfolders;
} else { } else {
// filter out empty lines and comments // filter out empty lines and comments
selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n').filter(QRegularExpression("\\S+")).filter(QRegularExpression("^[^#]")); selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n').filter(QRegExp("\\S+")).filter(QRegExp("^[^#]"));
for (int i = 0; i < selectiveSyncList.count(); ++i) { for (int i = 0; i < selectiveSyncList.count(); ++i) {
if (!selectiveSyncList.at(i).endsWith(QLatin1Char('/'))) { if (!selectiveSyncList.at(i).endsWith(QLatin1Char('/'))) {
@@ -501,9 +505,6 @@ restart_sync:
selectiveSyncFixup(&db, selectiveSyncList); selectiveSyncFixup(&db, selectiveSyncList);
} }
SyncOptions opt;
opt.fillFromEnvironmentVariables();
opt.verifyChunkSizes();
SyncEngine engine(account, options.source_dir, folder, &db); SyncEngine engine(account, options.source_dir, folder, &db);
engine.setIgnoreHiddenFiles(options.ignoreHiddenFiles); engine.setIgnoreHiddenFiles(options.ignoreHiddenFiles);
engine.setNetworkLimits(options.uplimit, options.downlimit); engine.setNetworkLimits(options.uplimit, options.downlimit);

View File

@@ -28,7 +28,7 @@ namespace OCC {
class SimpleSslErrorHandler : public OCC::AbstractSslErrorHandler class SimpleSslErrorHandler : public OCC::AbstractSslErrorHandler
{ {
public: public:
bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr) override; bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr) Q_DECL_OVERRIDE;
}; };
} }

View File

@@ -142,30 +142,21 @@ QByteArray makeChecksumHeader(const QByteArray &checksumType, const QByteArray &
return header; return header;
} }
QByteArray findBestChecksum(const QByteArray &_checksums) QByteArray findBestChecksum(const QByteArray &checksums)
{ {
if (_checksums.isEmpty()) {
return {};
}
const auto checksums = QString::fromUtf8(_checksums);
int i = 0; int i = 0;
// The order of the searches here defines the preference ordering. // The order of the searches here defines the preference ordering.
if (-1 != (i = checksums.indexOf(QLatin1String("SHA3-256:"), 0, Qt::CaseInsensitive)) if (-1 != (i = checksums.indexOf("SHA3-256:"))
|| -1 != (i = checksums.indexOf(QLatin1String("SHA256:"), 0, Qt::CaseInsensitive)) || -1 != (i = checksums.indexOf("SHA256:"))
|| -1 != (i = checksums.indexOf(QLatin1String("SHA1:"), 0, Qt::CaseInsensitive)) || -1 != (i = checksums.indexOf("SHA1:"))
|| -1 != (i = checksums.indexOf(QLatin1String("MD5:"), 0, Qt::CaseInsensitive)) || -1 != (i = checksums.indexOf("MD5:"))
|| -1 != (i = checksums.indexOf(QLatin1String("ADLER32:"), 0, Qt::CaseInsensitive))) { || -1 != (i = checksums.indexOf("Adler32:"))) {
// Now i is the start of the best checksum // Now i is the start of the best checksum
// Grab it until the next space or end of xml or end of string. // Grab it until the next space or end of string.
int end = _checksums.indexOf(' ', i); auto checksum = checksums.mid(i);
// workaround for https://github.com/owncloud/core/pull/38304 return checksum.mid(0, checksum.indexOf(" "));
if (end == -1) {
end = _checksums.indexOf('<', i);
}
return _checksums.mid(i, end - i);
} }
qCWarning(lcChecksums) << "Failed to parse" << _checksums; return QByteArray();
return {};
} }
bool parseChecksumHeader(const QByteArray &header, QByteArray *type, QByteArray *checksum) bool parseChecksumHeader(const QByteArray &header, QByteArray *type, QByteArray *checksum)
@@ -364,11 +355,11 @@ void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumTy
const QByteArray &checksum) const QByteArray &checksum)
{ {
if (checksumType != _expectedChecksumType) { if (checksumType != _expectedChecksumType) {
emit validationFailed(tr("The checksum header contained an unknown checksum type \"%1\"").arg(QString::fromLatin1(_expectedChecksumType))); emit validationFailed(tr("The checksum header contained an unknown checksum type '%1'").arg(QString::fromLatin1(_expectedChecksumType)));
return; return;
} }
if (checksum != _expectedChecksum) { if (checksum != _expectedChecksum) {
emit validationFailed(tr(R"(The downloaded file does not match the checksum, it will be resumed. "%1" != "%2")").arg(QString::fromUtf8(_expectedChecksum), QString::fromUtf8(checksum))); emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed. '%1' != '%2'").arg(QString::fromUtf8(_expectedChecksum), QString::fromUtf8(checksum)));
return; return;
} }
emit validated(checksumType, checksum); emit validated(checksumType, checksum);

View File

@@ -81,7 +81,7 @@ class OCSYNC_EXPORT ComputeChecksum : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ComputeChecksum(QObject *parent = nullptr); explicit ComputeChecksum(QObject *parent = nullptr);
~ComputeChecksum() override; ~ComputeChecksum();
/** /**
* Sets the checksum type to be used. The default is empty. * Sets the checksum type to be used. The default is empty.

View File

@@ -5,7 +5,6 @@ set(common_SOURCES
${CMAKE_CURRENT_LIST_DIR}/checksums.cpp ${CMAKE_CURRENT_LIST_DIR}/checksums.cpp
${CMAKE_CURRENT_LIST_DIR}/filesystembase.cpp ${CMAKE_CURRENT_LIST_DIR}/filesystembase.cpp
${CMAKE_CURRENT_LIST_DIR}/ownsql.cpp ${CMAKE_CURRENT_LIST_DIR}/ownsql.cpp
${CMAKE_CURRENT_LIST_DIR}/preparedsqlquerymanager.cpp
${CMAKE_CURRENT_LIST_DIR}/syncjournaldb.cpp ${CMAKE_CURRENT_LIST_DIR}/syncjournaldb.cpp
${CMAKE_CURRENT_LIST_DIR}/syncjournalfilerecord.cpp ${CMAKE_CURRENT_LIST_DIR}/syncjournalfilerecord.cpp
${CMAKE_CURRENT_LIST_DIR}/utility.cpp ${CMAKE_CURRENT_LIST_DIR}/utility.cpp

View File

@@ -1,23 +0,0 @@
/*
* Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#pragma once
#include <QtGlobal>
namespace OCC {
namespace Constants {
constexpr qint32 e2EeTagSize = 16;
}
}

View File

@@ -395,13 +395,13 @@ bool FileSystem::moveToTrash(const QString &fileName, QString *errorString)
suffix_number++; suffix_number++;
} }
if (!file.rename(f.absoluteFilePath(), path + QString::number(suffix_number))) { // rename(file old path, file trash path) if (!file.rename(f.absoluteFilePath(), path + QString::number(suffix_number))) { // rename(file old path, file trash path)
*errorString = QCoreApplication::translate("FileSystem", R"(Could not move "%1" to "%2")") *errorString = QCoreApplication::translate("FileSystem", "Could not move '%1' to '%2'")
.arg(f.absoluteFilePath(), path + QString::number(suffix_number)); .arg(f.absoluteFilePath(), path + QString::number(suffix_number));
return false; return false;
} }
} else { } else {
if (!file.rename(f.absoluteFilePath(), trashFilePath + f.fileName())) { // rename(file old path, file trash path) if (!file.rename(f.absoluteFilePath(), trashFilePath + f.fileName())) { // rename(file old path, file trash path)
*errorString = QCoreApplication::translate("FileSystem", R"(Could not move "%1" to "%2")") *errorString = QCoreApplication::translate("FileSystem", "Could not move '%1' to '%2'")
.arg(f.absoluteFilePath(), trashFilePath + f.fileName()); .arg(f.absoluteFilePath(), trashFilePath + f.fileName());
return false; return false;
} }

View File

@@ -490,4 +490,18 @@ void SqlQuery::reset_and_clear_bindings()
} }
} }
bool SqlQuery::initOrReset(const QByteArray &sql, OCC::SqlDatabase &db)
{
ENFORCE(!_sqldb || &db == _sqldb);
_sqldb = &db;
_db = db.sqliteDb();
if (_stmt) {
reset_and_clear_bindings();
return true;
} else {
return prepare(sql) == 0;
}
}
} // namespace OCC } // namespace OCC

View File

@@ -103,6 +103,12 @@ public:
explicit SqlQuery() = default; explicit SqlQuery() = default;
explicit SqlQuery(SqlDatabase &db); explicit SqlQuery(SqlDatabase &db);
explicit SqlQuery(const QByteArray &sql, SqlDatabase &db); explicit SqlQuery(const QByteArray &sql, SqlDatabase &db);
/**
* Prepare the SqlQuery if it was not prepared yet.
* Otherwise, clear the results and the bindings.
* return false if there is an error
*/
bool initOrReset(const QByteArray &sql, SqlDatabase &db);
/** /**
* Prepare the SqlQuery. * Prepare the SqlQuery.
* If the query was already prepared, this will first call finish(), and re-prepare it. * If the query was already prepared, this will first call finish(), and re-prepare it.
@@ -155,10 +161,10 @@ public:
const QByteArray &lastQuery() const; const QByteArray &lastQuery() const;
int numRowsAffected(); int numRowsAffected();
void reset_and_clear_bindings(); void reset_and_clear_bindings();
void finish();
private: private:
void bindValueInternal(int pos, const QVariant &value); void bindValueInternal(int pos, const QVariant &value);
void finish();
SqlDatabase *_sqldb = nullptr; SqlDatabase *_sqldb = nullptr;
sqlite3 *_db = nullptr; sqlite3 *_db = nullptr;
@@ -166,9 +172,6 @@ private:
QString _error; QString _error;
int _errId; int _errId;
QByteArray _sql; QByteArray _sql;
friend class SqlDatabase;
friend class PreparedSqlQueryManager;
}; };
} // namespace OCC } // namespace OCC

View File

@@ -77,7 +77,7 @@ enum class PinState {
*/ */
Unspecified = 3, Unspecified = 3,
}; };
Q_ENUM_NS(PinState) Q_ENUM_NS(PinState);
/** A user-facing version of PinState. /** A user-facing version of PinState.
* *

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "preparedsqlquerymanager.h"
#include <sqlite3.h>
using namespace OCC;
PreparedSqlQuery::PreparedSqlQuery(SqlQuery *query, bool ok)
: _query(query)
, _ok(ok)
{
}
PreparedSqlQuery::~PreparedSqlQuery()
{
_query->reset_and_clear_bindings();
}
const PreparedSqlQuery PreparedSqlQueryManager::get(PreparedSqlQueryManager::Key key)
{
auto &query = _queries[key];
ENFORCE(query._stmt)
Q_ASSERT(!sqlite3_stmt_busy(query._stmt));
return { &query };
}
const PreparedSqlQuery PreparedSqlQueryManager::get(PreparedSqlQueryManager::Key key, const QByteArray &sql, SqlDatabase &db)
{
auto &query = _queries[key];
Q_ASSERT(!sqlite3_stmt_busy(query._stmt));
ENFORCE(!query._sqldb || &db == query._sqldb)
if (!query._stmt) {
query._sqldb = &db;
query._db = db.sqliteDb();
return { &query, query.prepare(sql) == 0 };
}
return { &query };
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "ocsynclib.h"
#include "ownsql.h"
#include "common/asserts.h"
namespace OCC {
class OCSYNC_EXPORT PreparedSqlQuery
{
public:
~PreparedSqlQuery();
explicit operator bool() const { return _ok; }
SqlQuery *operator->() const
{
Q_ASSERT(_ok);
return _query;
}
SqlQuery &operator*() const &
{
Q_ASSERT(_ok);
return *_query;
}
private:
PreparedSqlQuery(SqlQuery *query, bool ok = true);
SqlQuery *_query;
bool _ok;
friend class PreparedSqlQueryManager;
};
/**
* @brief Manage PreparedSqlQuery
*/
class OCSYNC_EXPORT PreparedSqlQueryManager
{
public:
enum Key {
GetFileRecordQuery,
GetFileRecordQueryByMangledName,
GetFileRecordQueryByInode,
GetFileRecordQueryByFileId,
GetFilesBelowPathQuery,
GetAllFilesQuery,
ListFilesInPathQuery,
SetFileRecordQuery,
SetFileRecordChecksumQuery,
SetFileRecordLocalMetadataQuery,
GetDownloadInfoQuery,
SetDownloadInfoQuery,
DeleteDownloadInfoQuery,
GetUploadInfoQuery,
SetUploadInfoQuery,
DeleteUploadInfoQuery,
DeleteFileRecordPhash,
DeleteFileRecordRecursively,
GetErrorBlacklistQuery,
SetErrorBlacklistQuery,
GetSelectiveSyncListQuery,
GetChecksumTypeIdQuery,
GetChecksumTypeQuery,
InsertChecksumTypeQuery,
GetDataFingerprintQuery,
SetDataFingerprintQuery1,
SetDataFingerprintQuery2,
SetKeyValueStoreQuery,
GetKeyValueStoreQuery,
DeleteKeyValueStoreQuery,
GetConflictRecordQuery,
SetConflictRecordQuery,
DeleteConflictRecordQuery,
GetRawPinStateQuery,
GetEffectivePinStateQuery,
GetSubPinsQuery,
CountDehydratedFilesQuery,
SetPinStateQuery,
WipePinStateQuery,
PreparedQueryCount
};
PreparedSqlQueryManager() = default;
/**
* The queries are reset in the destructor to prevent wal locks
*/
const PreparedSqlQuery get(Key key);
/**
* Prepare the SqlQuery if it was not prepared yet.
*/
const PreparedSqlQuery get(Key key, const QByteArray &sql, SqlDatabase &db);
private:
SqlQuery _queries[PreparedQueryCount];
Q_DISABLE_COPY(PreparedSqlQueryManager)
};
}

View File

@@ -104,7 +104,6 @@ public:
ASSERT(!_isError); ASSERT(!_isError);
return _result; return _result;
} }
T operator*() && T operator*() &&
{ {
ASSERT(!_isError); ASSERT(!_isError);
@@ -117,12 +116,6 @@ public:
return &_result; return &_result;
} }
const T &get() const
{
ASSERT(!_isError)
return _result;
}
const Error &error() const & const Error &error() const &
{ {
ASSERT(_isError); ASSERT(_isError);

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,6 @@
#include "common/utility.h" #include "common/utility.h"
#include "common/ownsql.h" #include "common/ownsql.h"
#include "common/preparedsqlquerymanager.h"
#include "common/syncjournalfilerecord.h" #include "common/syncjournalfilerecord.h"
#include "common/result.h" #include "common/result.h"
#include "common/pinstate.h" #include "common/pinstate.h"
@@ -47,7 +46,7 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit SyncJournalDb(const QString &dbFilePath, QObject *parent = nullptr); explicit SyncJournalDb(const QString &dbFilePath, QObject *parent = nullptr);
~SyncJournalDb() override; virtual ~SyncJournalDb();
/// Create a journal path for a specific configuration /// Create a journal path for a specific configuration
static QString makeDbName(const QString &localPath, static QString makeDbName(const QString &localPath,
@@ -393,11 +392,51 @@ private:
SqlDatabase _db; SqlDatabase _db;
QString _dbFile; QString _dbFile;
QRecursiveMutex _mutex; // Public functions are protected with the mutex. QMutex _mutex; // Public functions are protected with the mutex.
QMap<QByteArray, int> _checksymTypeCache; QMap<QByteArray, int> _checksymTypeCache;
int _transaction; int _transaction;
bool _metadataTableIsEmpty; bool _metadataTableIsEmpty;
SqlQuery _getFileRecordQuery;
SqlQuery _getFileRecordQueryByMangledName;
SqlQuery _getFileRecordQueryByInode;
SqlQuery _getFileRecordQueryByFileId;
SqlQuery _getFilesBelowPathQuery;
SqlQuery _getAllFilesQuery;
SqlQuery _listFilesInPathQuery;
SqlQuery _setFileRecordQuery;
SqlQuery _setFileRecordChecksumQuery;
SqlQuery _setFileRecordLocalMetadataQuery;
SqlQuery _getDownloadInfoQuery;
SqlQuery _setDownloadInfoQuery;
SqlQuery _deleteDownloadInfoQuery;
SqlQuery _getUploadInfoQuery;
SqlQuery _setUploadInfoQuery;
SqlQuery _deleteUploadInfoQuery;
SqlQuery _deleteFileRecordPhash;
SqlQuery _deleteFileRecordRecursively;
SqlQuery _getErrorBlacklistQuery;
SqlQuery _setErrorBlacklistQuery;
SqlQuery _getSelectiveSyncListQuery;
SqlQuery _getChecksumTypeIdQuery;
SqlQuery _getChecksumTypeQuery;
SqlQuery _insertChecksumTypeQuery;
SqlQuery _getDataFingerprintQuery;
SqlQuery _setDataFingerprintQuery1;
SqlQuery _setDataFingerprintQuery2;
SqlQuery _setKeyValueStoreQuery;
SqlQuery _getKeyValueStoreQuery;
SqlQuery _deleteKeyValueStoreQuery;
SqlQuery _getConflictRecordQuery;
SqlQuery _setConflictRecordQuery;
SqlQuery _deleteConflictRecordQuery;
SqlQuery _getRawPinStateQuery;
SqlQuery _getEffectivePinStateQuery;
SqlQuery _getSubPinsQuery;
SqlQuery _countDehydratedFilesQuery;
SqlQuery _setPinStateQuery;
SqlQuery _wipePinStateQuery;
/* Storing etags to these folders, or their parent folders, is filtered out. /* Storing etags to these folders, or their parent folders, is filtered out.
* *
* When schedulePathForRemoteDiscovery() is called some etags to _invalid_ in the * When schedulePathForRemoteDiscovery() is called some etags to _invalid_ in the
@@ -419,8 +458,6 @@ private:
* variable, for specific filesystems, or when WAL fails in a particular way. * variable, for specific filesystems, or when WAL fails in a particular way.
*/ */
QByteArray _journalMode; QByteArray _journalMode;
PreparedSqlQueryManager _queryManager;
}; };
bool OCSYNC_EXPORT bool OCSYNC_EXPORT

View File

@@ -37,7 +37,6 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QCollator> #include <QCollator>
#include <QSysInfo> #include <QSysInfo>
#include <qrandom.h>
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
@@ -65,13 +64,14 @@ Q_LOGGING_CATEGORY(lcUtility, "nextcloud.sync.utility", QtInfoMsg)
bool Utility::writeRandomFile(const QString &fname, int size) bool Utility::writeRandomFile(const QString &fname, int size)
{ {
int maxSize = 10 * 10 * 1024; int maxSize = 10 * 10 * 1024;
qsrand(QDateTime::currentMSecsSinceEpoch());
if (size == -1) if (size == -1)
size = rand() % maxSize; size = qrand() % maxSize;
QString randString; QString randString;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int r = rand() % 128; int r = qrand() % 128;
randString.append(QChar(r)); randString.append(QChar(r));
} }
@@ -259,11 +259,6 @@ QString Utility::escape(const QString &in)
return in.toHtmlEscaped(); return in.toHtmlEscaped();
} }
int Utility::rand()
{
return QRandomGenerator::global()->bounded(0, RAND_MAX);
}
void Utility::sleep(int sec) void Utility::sleep(int sec)
{ {
QThread::sleep(sec); QThread::sleep(sec);

View File

@@ -50,7 +50,6 @@ Q_DECLARE_LOGGING_CATEGORY(lcUtility)
* @{ * @{
*/ */
namespace Utility { namespace Utility {
OCSYNC_EXPORT int rand();
OCSYNC_EXPORT void sleep(int sec); OCSYNC_EXPORT void sleep(int sec);
OCSYNC_EXPORT void usleep(int usec); OCSYNC_EXPORT void usleep(int usec);
OCSYNC_EXPORT QString formatFingerprint(const QByteArray &, bool colonSeparated = true); OCSYNC_EXPORT QString formatFingerprint(const QByteArray &, bool colonSeparated = true);

View File

@@ -80,17 +80,17 @@ void setLaunchOnStartup_private(const QString &appName, const QString &guiName,
QTextStream ts(&iniFile); QTextStream ts(&iniFile);
ts.setCodec("UTF-8"); ts.setCodec("UTF-8");
ts << QLatin1String("[Desktop Entry]\n") ts << QLatin1String("[Desktop Entry]") << endl
<< QLatin1String("Name=") << guiName << QLatin1Char('\n') << QLatin1String("Name=") << guiName << endl
<< QLatin1String("GenericName=") << QLatin1String("File Synchronizer\n") << QLatin1String("GenericName=") << QLatin1String("File Synchronizer") << endl
<< QLatin1String("Exec=\"") << executablePath << "\" --background\n" << QLatin1String("Exec=\"") << executablePath << "\" --background" << endl
<< QLatin1String("Terminal=") << "false\n" << QLatin1String("Terminal=") << "false" << endl
<< QLatin1String("Icon=") << APPLICATION_ICON_NAME << QLatin1Char('\n') << QLatin1String("Icon=") << APPLICATION_ICON_NAME << endl
<< QLatin1String("Categories=") << QLatin1String("Network\n") << QLatin1String("Categories=") << QLatin1String("Network") << endl
<< QLatin1String("Type=") << QLatin1String("Application\n") << QLatin1String("Type=") << QLatin1String("Application") << endl
<< QLatin1String("StartupNotify=") << "false\n" << QLatin1String("StartupNotify=") << "false" << endl
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true\n" << QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl
<< QLatin1String("X-GNOME-Autostart-Delay=10") << Qt::endl; << QLatin1String("X-GNOME-Autostart-Delay=10") << endl;
} else { } else {
if (!QFile::remove(desktopFileLocation)) { if (!QFile::remove(desktopFileLocation)) {
qCWarning(lcUtility) << "Could not remove autostart desktop file"; qCWarning(lcUtility) << "Could not remove autostart desktop file";

View File

@@ -16,7 +16,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "config.h"
#include "vfs.h" #include "vfs.h"
#include "plugin.h" #include "plugin.h"
#include "version.h" #include "version.h"

View File

@@ -126,7 +126,7 @@ public:
public: public:
explicit Vfs(QObject* parent = nullptr); explicit Vfs(QObject* parent = nullptr);
~Vfs() override; virtual ~Vfs();
virtual Mode mode() const = 0; virtual Mode mode() const = 0;
@@ -291,7 +291,7 @@ class OCSYNC_EXPORT VfsOff : public Vfs
public: public:
VfsOff(QObject* parent = nullptr); VfsOff(QObject* parent = nullptr);
~VfsOff() override; virtual ~VfsOff();
Mode mode() const override { return Vfs::Off; } Mode mode() const override { return Vfs::Off; }

View File

@@ -18,9 +18,7 @@
#include <libcrashreporter-gui/CrashReporter.h> #include <libcrashreporter-gui/CrashReporter.h>
#include <QApplication> #include <QApplication>
#include <QDir>
#include <QDebug> #include <QDebug>
#include <QFileInfo>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@@ -54,14 +52,6 @@ int main(int argc, char *argv[])
reporter.setWindowTitle(CRASHREPORTER_PRODUCT_NAME); reporter.setWindowTitle(CRASHREPORTER_PRODUCT_NAME);
reporter.setText("<html><head/><body><p><span style=\" font-weight:600;\">Sorry!</span> " CRASHREPORTER_PRODUCT_NAME " crashed. Please tell us about it! " CRASHREPORTER_PRODUCT_NAME " has created an error report for you that can help improve the stability in the future. You can now send this report directly to the " CRASHREPORTER_PRODUCT_NAME " developers.</p></body></html>"); reporter.setText("<html><head/><body><p><span style=\" font-weight:600;\">Sorry!</span> " CRASHREPORTER_PRODUCT_NAME " crashed. Please tell us about it! " CRASHREPORTER_PRODUCT_NAME " has created an error report for you that can help improve the stability in the future. You can now send this report directly to the " CRASHREPORTER_PRODUCT_NAME " developers.</p></body></html>");
const QFileInfo crashLog(QDir::tempPath() + QStringLiteral("/" CRASHREPORTER_PRODUCT_NAME "-crash.log"));
if (crashLog.exists()) {
QFile inFile(crashLog.filePath());
if (inFile.open(QFile::ReadOnly)) {
reporter.setComment(inFile.readAll());
}
}
reporter.setReportData("BuildID", CRASHREPORTER_BUILD_ID); reporter.setReportData("BuildID", CRASHREPORTER_BUILD_ID);
reporter.setReportData("ProductName", CRASHREPORTER_PRODUCT_NAME); reporter.setReportData("ProductName", CRASHREPORTER_PRODUCT_NAME);
reporter.setReportData("Version", CRASHREPORTER_VERSION_STRING); reporter.setReportData("Version", CRASHREPORTER_VERSION_STRING);

View File

@@ -58,11 +58,10 @@ endif()
configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h) configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
add_library(nextcloud_csync SHARED ${common_SOURCES} ${csync_SRCS}) add_library("${csync_NAME}" SHARED ${common_SOURCES} ${csync_SRCS})
add_library(Nextcloud::csync ALIAS nextcloud_csync)
target_include_directories( target_include_directories(
nextcloud_csync "${csync_NAME}"
PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/std PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/std
) )
@@ -70,26 +69,26 @@ if(USE_OUR_OWN_SQLITE3)
message(STATUS "Using own sqlite3 version") message(STATUS "Using own sqlite3 version")
add_library(sqlite3 STATIC "${CMAKE_SOURCE_DIR}/src/3rdparty/sqlite3/sqlite3.c") add_library(sqlite3 STATIC "${CMAKE_SOURCE_DIR}/src/3rdparty/sqlite3/sqlite3.c")
target_include_directories(sqlite3 PUBLIC "${CMAKE_SOURCE_DIR}/src/3rdparty/sqlite3") target_include_directories(sqlite3 PUBLIC "${CMAKE_SOURCE_DIR}/src/3rdparty/sqlite3")
target_link_libraries(nextcloud_csync PUBLIC sqlite3) target_link_libraries("${csync_NAME}" PUBLIC sqlite3)
else() else()
target_include_directories(nextcloud_csync PUBLIC ${SQLITE3_INCLUDE_DIR}) target_include_directories("${csync_NAME}" PUBLIC ${SQLITE3_INCLUDE_DIR})
target_link_libraries(nextcloud_csync PUBLIC ${SQLITE3_LIBRARIES}) target_link_libraries("${csync_NAME}" PUBLIC ${SQLITE3_LIBRARIES})
endif() endif()
generate_export_header(nextcloud_csync generate_export_header("${csync_NAME}"
EXPORT_MACRO_NAME OCSYNC_EXPORT EXPORT_MACRO_NAME OCSYNC_EXPORT
EXPORT_FILE_NAME ocsynclib.h EXPORT_FILE_NAME ocsynclib.h
) )
target_link_libraries(nextcloud_csync target_link_libraries("${csync_NAME}"
PUBLIC PUBLIC
${CSYNC_REQUIRED_LIBRARIES} ${CSYNC_REQUIRED_LIBRARIES}
Qt5::Core Qt5::Concurrent Qt5::Core Qt5::Concurrent
) )
if(ZLIB_FOUND) if(ZLIB_FOUND)
target_link_libraries(nextcloud_csync PUBLIC ZLIB::ZLIB) target_link_libraries("${csync_NAME}" PUBLIC ZLIB::ZLIB)
endif(ZLIB_FOUND) endif(ZLIB_FOUND)
@@ -97,11 +96,11 @@ endif(ZLIB_FOUND)
if (APPLE) if (APPLE)
find_library(FOUNDATION_LIBRARY NAMES Foundation) find_library(FOUNDATION_LIBRARY NAMES Foundation)
find_library(CORESERVICES_LIBRARY NAMES CoreServices) find_library(CORESERVICES_LIBRARY NAMES CoreServices)
target_link_libraries(nextcloud_csync PUBLIC ${FOUNDATION_LIBRARY} ${CORESERVICES_LIBRARY}) target_link_libraries("${csync_NAME}" PUBLIC ${FOUNDATION_LIBRARY} ${CORESERVICES_LIBRARY})
endif() endif()
set_target_properties( set_target_properties(
nextcloud_csync "${csync_NAME}"
PROPERTIES PROPERTIES
VERSION VERSION
${LIBRARY_VERSION} ${LIBRARY_VERSION}
@@ -109,15 +108,11 @@ set_target_properties(
${LIBRARY_SOVERSION} ${LIBRARY_SOVERSION}
RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY
${BIN_OUTPUT_DIRECTORY} ${BIN_OUTPUT_DIRECTORY}
LIBRARY_OUTPUT_NAME
${APPLICATION_EXECUTABLE}_csync
RUNTIME_OUTPUT_NAME
${APPLICATION_EXECUTABLE}_csync
) )
if(BUILD_OWNCLOUD_OSX_BUNDLE) if(BUILD_OWNCLOUD_OSX_BUNDLE)
INSTALL( INSTALL(
TARGETS TARGETS
nextcloud_csync "${csync_NAME}"
LIBRARY DESTINATION LIBRARY DESTINATION
${LIB_INSTALL_DIR} ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ARCHIVE DESTINATION
@@ -128,7 +123,7 @@ if(BUILD_OWNCLOUD_OSX_BUNDLE)
else() else()
INSTALL( INSTALL(
TARGETS TARGETS
nextcloud_csync "${csync_NAME}"
LIBRARY DESTINATION LIBRARY DESTINATION
${CMAKE_INSTALL_LIBDIR} ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ARCHIVE DESTINATION

View File

@@ -7,6 +7,7 @@ include(CheckCXXSourceCompiles)
set(PACKAGE ${APPLICATION_NAME}) set(PACKAGE ${APPLICATION_NAME})
set(VERSION ${APPLICATION_VERSION}) set(VERSION ${APPLICATION_VERSION})
set(DATADIR ${DATA_INSTALL_DIR})
set(LIBDIR ${LIB_INSTALL_DIR}) set(LIBDIR ${LIB_INSTALL_DIR})
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
@@ -22,12 +23,6 @@ if (NOT LINUX)
check_library_exists(rt nanosleep "" HAVE_LIBRT) check_library_exists(rt nanosleep "" HAVE_LIBRT)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} )
# Systems not using glibc require linker flag for argp
check_library_exists(argp argp_parse "" HAVE_LIBARGP)
if(HAVE_ARGP_H AND HAVE_LIBARGP)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} argp)
endif()
endif (NOT LINUX) endif (NOT LINUX)
if(WIN32) if(WIN32)

View File

@@ -19,7 +19,6 @@
*/ */
#include "config_csync.h" #include "config_csync.h"
#include <qglobal.h>
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
@@ -35,8 +34,10 @@
#include <QString> #include <QString>
#include <QFileInfo> #include <QFileInfo>
#include <QFile>
#include <QDir> #include <QDir>
/** Expands C-like escape sequences (in place) /** Expands C-like escape sequences (in place)
*/ */
OCSYNC_EXPORT void csync_exclude_expand_escapes(QByteArray &input) OCSYNC_EXPORT void csync_exclude_expand_escapes(QByteArray &input)
@@ -198,13 +199,13 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const QString &path, bool exclu
} }
#endif #endif
/* Do not sync desktop.ini files anywhere in the tree. */ /* We create a Desktop.ini on Windows for the sidebar icon, make sure we don't sync it. */
const auto desktopIniFile = QStringLiteral("desktop.ini"); if (blen == 11 && path == bname) {
if (blen == static_cast<qsizetype>(desktopIniFile.length()) && bname.compare(desktopIniFile, Qt::CaseInsensitive) == 0) { if (bname.compare(QLatin1String("Desktop.ini"), Qt::CaseInsensitive) == 0) {
return CSYNC_FILE_SILENTLY_EXCLUDED; return CSYNC_FILE_SILENTLY_EXCLUDED;
}
} }
if (excludeConflictFiles && OCC::Utility::isConflictFile(path)) { if (excludeConflictFiles && OCC::Utility::isConflictFile(path)) {
return CSYNC_FILE_EXCLUDE_CONFLICT; return CSYNC_FILE_EXCLUDE_CONFLICT;
} }
@@ -230,21 +231,24 @@ ExcludedFiles::ExcludedFiles(const QString &localPath)
// We're in a detached exclude probably coming from a partial sync or test // We're in a detached exclude probably coming from a partial sync or test
if (_localPath.isEmpty()) if (_localPath.isEmpty())
return; return;
// Load exclude file from base dir
QFileInfo fi(_localPath + QStringLiteral(".sync-exclude.lst"));
if (fi.isReadable())
addInTreeExcludeFilePath(fi.absoluteFilePath());
} }
ExcludedFiles::~ExcludedFiles() = default; ExcludedFiles::~ExcludedFiles() = default;
void ExcludedFiles::addExcludeFilePath(const QString &path) void ExcludedFiles::addExcludeFilePath(const QString &path)
{ {
const QFileInfo excludeFileInfo(path); _excludeFiles[_localPath].append(path);
const auto fileName = excludeFileInfo.fileName(); }
const auto basePath = fileName.compare(QStringLiteral("sync-exclude.lst"), Qt::CaseInsensitive) == 0
? _localPath void ExcludedFiles::addInTreeExcludeFilePath(const QString &path)
: leftIncludeLast(path, QLatin1Char('/')); {
auto &excludeFilesLocalPath = _excludeFiles[basePath]; BasePathString basePath = leftIncludeLast(path, QLatin1Char('/'));
if (std::find(excludeFilesLocalPath.cbegin(), excludeFilesLocalPath.cend(), path) == excludeFilesLocalPath.cend()) { _excludeFiles[basePath].append(path);
excludeFilesLocalPath.append(path);
}
} }
void ExcludedFiles::setExcludeConflictFiles(bool onoff) void ExcludedFiles::setExcludeConflictFiles(bool onoff)
@@ -284,26 +288,32 @@ void ExcludedFiles::setClientVersion(ExcludedFiles::Version version)
_clientVersion = version; _clientVersion = version;
} }
void ExcludedFiles::loadExcludeFilePatterns(const QString &basePath, QFile &file) bool ExcludedFiles::loadExcludeFile(const QString &basePath, const QString & file)
{ {
QFile f(file);
if (!f.open(QIODevice::ReadOnly))
return false;
QStringList patterns; QStringList patterns;
while (!file.atEnd()) { while (!f.atEnd()) {
QByteArray line = file.readLine().trimmed(); QByteArray line = f.readLine().trimmed();
if (line.startsWith("#!version")) { if (line.startsWith("#!version")) {
if (!versionDirectiveKeepNextLine(line)) if (!versionDirectiveKeepNextLine(line))
file.readLine(); f.readLine();
} }
if (line.isEmpty() || line.startsWith('#')) if (line.isEmpty() || line.startsWith('#'))
continue; continue;
csync_exclude_expand_escapes(line); csync_exclude_expand_escapes(line);
patterns.append(QString::fromUtf8(line)); patterns.append(QString::fromUtf8(line));
} }
_allExcludes[basePath].append(patterns); _allExcludes.insert(basePath, patterns);
// nothing to prepare if the user decided to not exclude anything // nothing to prepare if the user decided to not exclude anything
if (!_allExcludes.value(basePath).isEmpty()){ if (!_allExcludes.value(basePath).isEmpty()){
prepare(basePath); prepare(basePath);
} }
return true;
} }
bool ExcludedFiles::reloadExcludeFiles() bool ExcludedFiles::reloadExcludeFiles()
@@ -320,14 +330,8 @@ bool ExcludedFiles::reloadExcludeFiles()
bool success = true; bool success = true;
const auto keys = _excludeFiles.keys(); const auto keys = _excludeFiles.keys();
for (const auto& basePath : keys) { for (const auto& basePath : keys) {
for (const auto &excludeFile : _excludeFiles.value(basePath)) { for (const auto& file : _excludeFiles.value(basePath)) {
QFile file(excludeFile); success = loadExcludeFile(basePath, file);
if (file.exists() && file.open(QIODevice::ReadOnly)) {
loadExcludeFilePatterns(basePath, file);
} else {
success = false;
qWarning() << "System exclude list file could not be opened:" << excludeFile;
}
} }
} }
@@ -418,14 +422,11 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const QString &path, Ite
// Directories are guaranteed to be visited before their files // Directories are guaranteed to be visited before their files
if (filetype == ItemTypeDirectory) { if (filetype == ItemTypeDirectory) {
const auto basePath = QString(_localPath + path + QLatin1Char('/')); const auto basePath = QString(_localPath + path + QLatin1Char('/'));
const QString absolutePath = basePath + QStringLiteral(".sync-exclude.lst"); const auto fi = QFileInfo(basePath + QStringLiteral(".sync-exclude.lst"));
QFileInfo excludeFileInfo(absolutePath);
if (excludeFileInfo.isReadable()) { if (fi.isReadable()) {
addExcludeFilePath(absolutePath); addInTreeExcludeFilePath(fi.absoluteFilePath());
reloadExcludeFiles(); loadExcludeFile(basePath, fi.absoluteFilePath());
} else {
qWarning() << "System exclude list file could not be read:" << absolutePath;
} }
} }

View File

@@ -48,7 +48,6 @@ enum CSYNC_EXCLUDE_TYPE {
}; };
class ExcludedFilesTest; class ExcludedFilesTest;
class QFile;
/** /**
* Manages file/directory exclusion. * Manages file/directory exclusion.
@@ -70,7 +69,7 @@ public:
using Version = std::tuple<int, int, int>; using Version = std::tuple<int, int, int>;
explicit ExcludedFiles(const QString &localPath = QStringLiteral("/")); explicit ExcludedFiles(const QString &localPath = QStringLiteral("/"));
~ExcludedFiles() override; ~ExcludedFiles();
/** /**
* Adds a new path to a file containing exclude patterns. * Adds a new path to a file containing exclude patterns.
@@ -78,6 +77,7 @@ public:
* Does not load the file. Use reloadExcludeFiles() afterwards. * Does not load the file. Use reloadExcludeFiles() afterwards.
*/ */
void addExcludeFilePath(const QString &path); void addExcludeFilePath(const QString &path);
void addInTreeExcludeFilePath(const QString &path);
/** /**
* Whether conflict files shall be excluded. * Whether conflict files shall be excluded.
@@ -148,7 +148,7 @@ public slots:
/** /**
* Loads the exclude patterns from file the registered base paths. * Loads the exclude patterns from file the registered base paths.
*/ */
void loadExcludeFilePatterns(const QString &basePath, QFile &file); bool loadExcludeFile(const QString &basePath, const QString &file);
private: private:
/** /**

View File

@@ -124,8 +124,7 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
if (vfs) { if (vfs) {
// Directly modifies file_stat->type. // Directly modifies file_stat->type.
// We can ignore the return value since we're done here anyway. // We can ignore the return value since we're done here anyway.
const auto result = vfs->statTypeVirtualFile(file_stat.get(), &handle->path); vfs->statTypeVirtualFile(file_stat.get(), &handle->path);
Q_UNUSED(result)
} }
return file_stat; return file_stat;

View File

@@ -34,7 +34,6 @@
#include "csync.h" #include "csync.h"
#include "vio/csync_vio_local.h" #include "vio/csync_vio_local.h"
#include "common/filesystembase.h" #include "common/filesystembase.h"
#include "common/utility.h"
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
@@ -53,6 +52,8 @@ struct csync_vio_handle_t {
QString path; // Always ends with '\' QString path; // Always ends with '\'
}; };
static int _csync_vio_local_stat_mb(const QString &path, csync_file_stat_t *buf);
csync_vio_handle_t *csync_vio_local_opendir(const QString &name) { csync_vio_handle_t *csync_vio_local_opendir(const QString &name) {
QScopedPointer<csync_vio_handle_t> handle(new csync_vio_handle_t{}); QScopedPointer<csync_vio_handle_t> handle(new csync_vio_handle_t{});
@@ -174,9 +175,12 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow;
file_stat->modtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); file_stat->modtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem);
// path always ends with '\', by construction QString fullPath;
fullPath.reserve(handle->path.size() + std::wcslen(handle->ffd.cFileName));
fullPath += handle->path; // path always ends with '\', by construction
fullPath += QString::fromWCharArray(handle->ffd.cFileName);
if (csync_vio_local_stat(handle->path + QString::fromWCharArray(handle->ffd.cFileName), file_stat.get()) < 0) { if (_csync_vio_local_stat_mb(fullPath, file_stat.get()) < 0) {
// Will get excluded by _csync_detect_update. // Will get excluded by _csync_detect_update.
file_stat->type = ItemTypeSkip; file_stat->type = ItemTypeSkip;
} }
@@ -184,7 +188,14 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
return file_stat; return file_stat;
} }
int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf) int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf)
{
int rc = _csync_vio_local_stat_mb(uri, buf);
return rc;
}
static int _csync_vio_local_stat_mb(const QString &path, csync_file_stat_t *buf)
{ {
/* Almost nothing to do since csync_vio_local_readdir already filled up most of the information /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information
But we still need to fetch the file ID. But we still need to fetch the file ID.
@@ -195,19 +206,21 @@ int csync_vio_local_stat(const QString &uri, csync_file_stat_t *buf)
BY_HANDLE_FILE_INFORMATION fileInfo; BY_HANDLE_FILE_INFORMATION fileInfo;
ULARGE_INTEGER FileIndex; ULARGE_INTEGER FileIndex;
h = CreateFileW(reinterpret_cast<const wchar_t *>(OCC::FileSystem::longWinPath(uri).utf16()), 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, const auto longPath = OCC::FileSystem::longWinPath(path);
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, h = CreateFileW(longPath.toStdWString().data(), 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL); nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr );
if( h == INVALID_HANDLE_VALUE ) { if( h == INVALID_HANDLE_VALUE ) {
qCCritical(lcCSyncVIOLocal) << "CreateFileW failed on" << longPath;
errno = GetLastError(); errno = GetLastError();
qCCritical(lcCSyncVIOLocal) << "CreateFileW failed on" << uri << OCC::Utility::formatWinError(errno);
return -1; return -1;
} }
if(!GetFileInformationByHandle( h, &fileInfo ) ) { if(!GetFileInformationByHandle( h, &fileInfo ) ) {
qCCritical(lcCSyncVIOLocal) << "GetFileInformationByHandle failed on" << longPath;
errno = GetLastError(); errno = GetLastError();
qCCritical(lcCSyncVIOLocal) << "GetFileInformationByHandle failed on" << uri << OCC::Utility::formatWinError(errno);
CloseHandle(h); CloseHandle(h);
return -1; return -1;
} }

View File

@@ -18,7 +18,6 @@ set(theme_dir ${CMAKE_SOURCE_DIR}/theme)
set(client_UI_SRCS set(client_UI_SRCS
accountsettings.ui accountsettings.ui
conflictdialog.ui conflictdialog.ui
invalidfilenamedialog.ui
foldercreationdialog.ui foldercreationdialog.ui
folderwizardsourcepage.ui folderwizardsourcepage.ui
folderwizardtargetpage.ui folderwizardtargetpage.ui
@@ -36,27 +35,17 @@ set(client_UI_SRCS
addcertificatedialog.ui addcertificatedialog.ui
proxyauthdialog.ui proxyauthdialog.ui
mnemonicdialog.ui mnemonicdialog.ui
UserStatusSelector.qml
UserStatusSelectorDialog.qml
tray/ActivityActionButton.qml tray/ActivityActionButton.qml
tray/ActivityItem.qml tray/ActivityItem.qml
tray/ActivityList.qml
tray/Window.qml tray/Window.qml
tray/UserLine.qml tray/UserLine.qml
tray/UnifiedSearchInputContainer.qml
tray/UnifiedSearchResultFetchMoreTrigger.qml
tray/UnifiedSearchResultItem.qml
tray/UnifiedSearchResultItemSkeleton.qml
tray/UnifiedSearchResultItemSkeletonContainer.qml
tray/UnifiedSearchResultListItem.qml
tray/UnifiedSearchResultNothingFound.qml
tray/UnifiedSearchResultSectionItem.qml
wizard/flow2authwidget.ui wizard/flow2authwidget.ui
wizard/owncloudadvancedsetuppage.ui wizard/owncloudadvancedsetuppage.ui
wizard/owncloudconnectionmethoddialog.ui wizard/owncloudconnectionmethoddialog.ui
wizard/owncloudhttpcredspage.ui wizard/owncloudhttpcredspage.ui
wizard/owncloudoauthcredspage.ui wizard/owncloudoauthcredspage.ui
wizard/owncloudsetupnocredspage.ui wizard/owncloudsetupnocredspage.ui
wizard/owncloudwizardresultpage.ui
wizard/webview.ui wizard/webview.ui
wizard/welcomepage.ui wizard/welcomepage.ui
) )
@@ -65,7 +54,6 @@ set(client_SRCS
accountmanager.cpp accountmanager.cpp
accountsettings.cpp accountsettings.cpp
application.cpp application.cpp
invalidfilenamedialog.cpp
conflictdialog.cpp conflictdialog.cpp
conflictsolver.cpp conflictsolver.cpp
connectionvalidator.cpp connectionvalidator.cpp
@@ -98,14 +86,15 @@ set(client_SRCS
sharelinkwidget.cpp sharelinkwidget.cpp
sharemanager.cpp sharemanager.cpp
shareusergroupwidget.cpp shareusergroupwidget.cpp
profilepagewidget.cpp
sharee.cpp sharee.cpp
socketapi.cpp
sslbutton.cpp sslbutton.cpp
sslerrordialog.cpp sslerrordialog.cpp
syncrunfilelog.cpp syncrunfilelog.cpp
systray.cpp systray.cpp
thumbnailjob.cpp thumbnailjob.cpp
userinfo.cpp userinfo.cpp
userstatus.cpp
accountstate.cpp accountstate.cpp
addcertificatedialog.cpp addcertificatedialog.cpp
authenticationdialog.cpp authenticationdialog.cpp
@@ -116,21 +105,13 @@ set(client_SRCS
guiutility.cpp guiutility.cpp
elidedlabel.cpp elidedlabel.cpp
headerbanner.cpp headerbanner.cpp
iconutils.cpp iconjob.cpp
remotewipe.cpp remotewipe.cpp
userstatusselectormodel.cpp tray/ActivityData.cpp
emojimodel.cpp tray/ActivityListModel.cpp
fileactivitylistmodel.cpp tray/UserModel.cpp
tray/svgimageprovider.cpp tray/NotificationHandler.cpp
tray/syncstatussummary.cpp tray/NotificationCache.cpp
tray/activitydata.cpp
tray/activitylistmodel.cpp
tray/unifiedsearchresult.cpp
tray/unifiedsearchresultimageprovider.cpp
tray/unifiedsearchresultslistmodel.cpp
tray/usermodel.cpp
tray/notificationhandler.cpp
tray/notificationcache.cpp
creds/credentialsfactory.cpp creds/credentialsfactory.cpp
creds/httpcredentialsgui.cpp creds/httpcredentialsgui.cpp
creds/oauth.cpp creds/oauth.cpp
@@ -148,6 +129,7 @@ set(client_SRCS
wizard/owncloudsetuppage.cpp wizard/owncloudsetuppage.cpp
wizard/owncloudwizardcommon.cpp wizard/owncloudwizardcommon.cpp
wizard/owncloudwizard.cpp wizard/owncloudwizard.cpp
wizard/owncloudwizardresultpage.cpp
wizard/slideshow.cpp wizard/slideshow.cpp
wizard/welcomepage.cpp wizard/welcomepage.cpp
wizard/linklabel.cpp wizard/linklabel.cpp
@@ -170,6 +152,7 @@ endif()
IF( APPLE ) IF( APPLE )
list(APPEND client_SRCS cocoainitializer_mac.mm) list(APPEND client_SRCS cocoainitializer_mac.mm)
list(APPEND client_SRCS socketapisocket_mac.mm)
list(APPEND client_SRCS systray.mm) list(APPEND client_SRCS systray.mm)
if(SPARKLE_FOUND AND BUILD_UPDATER) if(SPARKLE_FOUND AND BUILD_UPDATER)
@@ -255,13 +238,13 @@ if (NOT DEFINED APPLICATION_ICON_NAME)
endif() endif()
# Generate png icons from svg # Generate png icons from svg
find_program(SVG_CONVERTER find_program(INKSCAPE
NAMES inkscape inkscape.exe rsvg-convert NAMES inkscape inkscape.exe
REQUIRED REQUIRED
HINTS "C:\\Program Files\\Inkscape\\bin" "/usr/bin" ENV SVG_CONVERTER_DIR) HINTS "C:\\Program Files\\Inkscape\\bin" "/usr/bin" ENV INKSCAPE_DIR)
# REQUIRED keyword is only supported on CMake 3.18 and above # REQUIRED keyword is only supported on CMake 3.18 and above
if (NOT SVG_CONVERTER) if (NOT INKSCAPE)
message(FATAL_ERROR "Could not find a suitable svg converter. Set SVG_CONVERTER_DIR to the path of either the inkscape or rsvg-convert executable.") message(FATAL_ERROR "Could not find inkscape. Set INKSCAPE_DIR to the path of executable.")
endif() endif()
function(generate_sized_png_from_svg icon_path size) function(generate_sized_png_from_svg icon_path size)
@@ -275,16 +258,16 @@ function(generate_sized_png_from_svg icon_path size)
set(icon_output_name "${size}-${icon_name_wle}.png") set(icon_output_name "${size}-${icon_name_wle}.png")
message(STATUS "Generate ${icon_output_name}") message(STATUS "Generate ${icon_output_name}")
execute_process(COMMAND execute_process(COMMAND
"${SVG_CONVERTER}" -w ${size} -h ${size} "${icon_path}" -o "${icon_output_name}" "${INKSCAPE}" -w ${size} -h ${size} "${icon_path}" -o "${icon_output_name}"
WORKING_DIRECTORY "${icon_name_dir}" WORKING_DIRECTORY "${icon_name_dir}"
RESULT_VARIABLE RESULT_VARIABLE
SVG_CONVERTER_SIDEBAR_ERROR INKSCAPE_SIDEBAR_ERROR
OUTPUT_QUIET OUTPUT_QUIET
ERROR_QUIET) ERROR_QUIET)
if (SVG_CONVERTER_SIDEBAR_ERROR) if (INKSCAPE_SIDEBAR_ERROR)
message(FATAL_ERROR message(FATAL_ERROR
"${SVG_CONVERTER} could not generate icon: ${SVG_CONVERTER_SIDEBAR_ERROR}") "inkscape could not generate icon: ${INKSCAPE_SIDEBAR_ERROR}")
else() else()
endif() endif()
endfunction() endfunction()
@@ -344,7 +327,6 @@ add_library(nextcloudCore STATIC ${final_src})
target_link_libraries(nextcloudCore target_link_libraries(nextcloudCore
PUBLIC PUBLIC
Nextcloud::sync
Qt5::Widgets Qt5::Widgets
Qt5::GuiPrivate Qt5::GuiPrivate
Qt5::Svg Qt5::Svg
@@ -353,10 +335,9 @@ target_link_libraries(nextcloudCore
Qt5::Qml Qt5::Qml
Qt5::Quick Qt5::Quick
Qt5::QuickControls2 Qt5::QuickControls2
${synclib_NAME}
) )
add_subdirectory(socketapi)
if(Qt5WebEngine_FOUND AND Qt5WebEngineWidgets_FOUND) if(Qt5WebEngine_FOUND AND Qt5WebEngineWidgets_FOUND)
target_link_libraries(nextcloudCore PUBLIC Qt5::WebEngineWidgets) target_link_libraries(nextcloudCore PUBLIC Qt5::WebEngineWidgets)
endif() endif()
@@ -384,9 +365,9 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
foreach(_file ${_icons}) foreach(_file ${_icons})
string(REPLACE "${theme_dir}/colored/" "" _res ${_file}) string(REPLACE "${theme_dir}/colored/" "" _res ${_file})
string(REPLACE "-${APPLICATION_ICON_NAME}-icon.png" "" _res ${_res}) string(REPLACE "-${APPLICATION_ICON_NAME}-icon.png" "" _res ${_res})
install(FILES ${_file} RENAME ${APPLICATION_ICON_NAME}.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${_res}x${_res}/apps) install(FILES ${_file} RENAME ${APPLICATION_ICON_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps)
endforeach(_file) endforeach(_file)
install(FILES ${client_I18N} DESTINATION ${CMAKE_INSTALL_DATADIR}/${APPLICATION_EXECUTABLE}/i18n) install(FILES ${client_I18N} DESTINATION ${SHAREDIR}/${APPLICATION_EXECUTABLE}/i18n)
else() else()
file(GLOB_RECURSE VISUAL_ELEMENTS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-w10startmenu*") file(GLOB_RECURSE VISUAL_ELEMENTS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-w10startmenu*")
install(FILES ${VISUAL_ELEMENTS} DESTINATION bin/visualelements) install(FILES ${VISUAL_ELEMENTS} DESTINATION bin/visualelements)
@@ -395,23 +376,17 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
endif() endif()
# we may not add MACOSX_BUNDLE here, if not building one # we may not add MACOSX_BUNDLE here, if not building one
add_executable(nextcloud WIN32 main.cpp ${client_version} ${client_manifest} ${APP_ICON}) add_executable(${APPLICATION_EXECUTABLE} WIN32 main.cpp ${client_version} ${client_manifest} ${APP_ICON})
set_target_properties(nextcloud PROPERTIES
OUTPUT_NAME "${APPLICATION_EXECUTABLE}"
)
else() else()
# set(CMAKE_INSTALL_PREFIX ".") # Examples use /Applications. hurmpf. # set(CMAKE_INSTALL_PREFIX ".") # Examples use /Applications. hurmpf.
set(MACOSX_BUNDLE_ICON_FILE "${APPLICATION_ICON_NAME}.icns") set(MACOSX_BUNDLE_ICON_FILE "${APPLICATION_ICON_NAME}.icns")
# we must add MACOSX_BUNDLE only if building a bundle # we must add MACOSX_BUNDLE only if building a bundle
add_executable(nextcloud WIN32 MACOSX_BUNDLE main.cpp ${APP_ICON}) add_executable(${APPLICATION_EXECUTABLE} WIN32 MACOSX_BUNDLE main.cpp ${APP_ICON})
if (BUILD_OWNCLOUD_OSX_BUNDLE) if (BUILD_OWNCLOUD_OSX_BUNDLE)
set_target_properties(nextcloud PROPERTIES set_target_properties(${APPLICATION_EXECUTABLE} PROPERTIES
OUTPUT_NAME "${APPLICATION_NAME}") OUTPUT_NAME "${APPLICATION_NAME}")
else()
set_target_properties(nextcloud PROPERTIES
OUTPUT_NAME "${APPLICATION_EXECUTABLE}")
endif() endif()
set (QM_DIR ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/Translations) set (QM_DIR ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/Translations)
@@ -431,17 +406,22 @@ endif()
IF(BUILD_UPDATER) IF(BUILD_UPDATER)
add_library(updater STATIC ${updater_SRCS}) add_library(updater STATIC ${updater_SRCS})
target_link_libraries(updater Nextcloud::sync ${updater_DEPS} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml) target_link_libraries(updater ${synclib_NAME} ${updater_DEPS} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml)
target_include_directories(updater PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(updater PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(updater PROPERTIES AUTOMOC ON) set_target_properties(updater PROPERTIES AUTOMOC ON)
target_link_libraries(nextcloudCore PUBLIC updater)
endif() endif()
set_target_properties(nextcloud PROPERTIES set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
) )
target_link_libraries(nextcloud PRIVATE nextcloudCore) target_link_libraries(${APPLICATION_EXECUTABLE} nextcloudCore)
IF(BUILD_UPDATER)
target_link_libraries(nextcloudCore PUBLIC updater)
endif()
target_link_libraries(nextcloudCore PUBLIC ${OS_SPECIFIC_LINK_LIBRARIES})
if(TARGET PkgConfig::CLOUDPROVIDERS) if(TARGET PkgConfig::CLOUDPROVIDERS)
message("Building with libcloudproviderssupport") message("Building with libcloudproviderssupport")
@@ -487,7 +467,11 @@ if(WITH_CRASHREPORTER)
endif() endif()
endif() endif()
install(TARGETS nextcloud # application.cpp still uses QDesktopServices::storageLocation
target_compile_definitions(nextcloudCore PRIVATE "QT_DISABLE_DEPRECATED_BEFORE=0")
install(TARGETS ${APPLICATION_EXECUTABLE}
RUNTIME DESTINATION bin RUNTIME DESTINATION bin
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
@@ -514,12 +498,12 @@ if(BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
set(NO_STRIP "") set(NO_STRIP "")
endif() endif()
add_custom_command(TARGET nextcloud POST_BUILD add_custom_command(TARGET ${APPLICATION_EXECUTABLE} POST_BUILD
COMMAND "${MACDEPLOYQT_EXECUTABLE}" COMMAND "${MACDEPLOYQT_EXECUTABLE}"
"$<TARGET_FILE_DIR:nextcloud>/../.." "$<TARGET_FILE_DIR:${APPLICATION_EXECUTABLE}>/../.."
-qmldir=${CMAKE_SOURCE_DIR}/src/gui -qmldir=${CMAKE_SOURCE_DIR}/src/gui
-always-overwrite -always-overwrite
-executable="$<TARGET_FILE_DIR:nextcloud>/${cmd_NAME}" -executable="$<TARGET_FILE_DIR:${APPLICATION_EXECUTABLE}>/${cmd_NAME}"
${NO_STRIP} ${NO_STRIP}
COMMAND "${CMAKE_COMMAND}" COMMAND "${CMAKE_COMMAND}"
-E rm -rf "${BIN_OUTPUT_DIRECTORY}/${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns/bearer" -E rm -rf "${BIN_OUTPUT_DIRECTORY}/${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns/bearer"
@@ -530,13 +514,13 @@ endif()
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE AND NOT WIN32) if(NOT BUILD_OWNCLOUD_OSX_BUNDLE AND NOT WIN32)
configure_file(${CMAKE_SOURCE_DIR}/mirall.desktop.in configure_file(${CMAKE_SOURCE_DIR}/mirall.desktop.in
${CMAKE_CURRENT_BINARY_DIR}/${LINUX_APPLICATION_ID}.desktop) ${CMAKE_CURRENT_BINARY_DIR}/${LINUX_APPLICATION_ID}.desktop)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LINUX_APPLICATION_ID}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LINUX_APPLICATION_ID}.desktop DESTINATION ${DATADIR}/applications )
configure_file(owncloud.xml.in ${APPLICATION_EXECUTABLE}.xml) configure_file(owncloud.xml.in ${APPLICATION_EXECUTABLE}.xml)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_EXECUTABLE}.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_EXECUTABLE}.xml DESTINATION ${DATADIR}/mime/packages )
find_package(SharedMimeInfo) find_package(SharedMimeInfo)
if(SharedMimeInfo_FOUND) if(SharedMimeInfo_FOUND)
update_xdg_mimetypes( ${CMAKE_INSTALL_DATADIR}/mime/packages ) update_xdg_mimetypes( ${DATADIR}/mime/packages )
endif(SharedMimeInfo_FOUND) endif(SharedMimeInfo_FOUND)
endif() endif()

View File

@@ -1,112 +0,0 @@
/*
* Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import com.nextcloud.desktopclient 1.0 as NC
ColumnLayout {
NC.EmojiModel {
id: emojiModel
}
signal chosen(string emoji)
spacing: 0
FontMetrics {
id: metrics
}
ListView {
id: headerLayout
Layout.fillWidth: true
implicitWidth: contentItem.childrenRect.width
implicitHeight: metrics.height * 2
orientation: ListView.Horizontal
model: emojiModel.emojiCategoriesModel
delegate: ItemDelegate {
width: metrics.height * 2
height: headerLayout.height
contentItem: Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: emoji
}
Rectangle {
anchors.bottom: parent.bottom
width: parent.width
height: 2
visible: ListView.isCurrentItem
color: "grey"
}
onClicked: {
emojiModel.setCategory(label)
}
}
}
Rectangle {
height: 1
Layout.fillWidth: true
color: "grey"
}
GridView {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: metrics.height * 8
cellWidth: metrics.height * 2
cellHeight: metrics.height * 2
boundsBehavior: Flickable.DragOverBounds
clip: true
model: emojiModel.model
delegate: ItemDelegate {
width: metrics.height * 2
height: metrics.height * 2
contentItem: Text {
anchors.centerIn: parent
text: modelData === undefined ? "" : modelData.unicode
}
onClicked: {
chosen(modelData.unicode);
emojiModel.emojiUsed(modelData);
}
}
ScrollBar.vertical: ScrollBar {}
}
}

View File

@@ -1,32 +0,0 @@
import QtQuick 2.15
import Style 1.0
Item {
id: errorBox
property var text: ""
property color color: Style.errorBoxTextColor
property color backgroundColor: Style.errorBoxBackgroundColor
property color borderColor: Style.errorBoxBorderColor
implicitHeight: errorMessage.implicitHeight + 2 * 8
Rectangle {
anchors.fill: parent
color: errorBox.backgroundColor
border.color: errorBox.borderColor
}
Text {
id: errorMessage
anchors.fill: parent
anchors.margins: 8
width: parent.width
color: errorBox.color
wrapMode: Text.WordWrap
text: errorBox.text
}
}

View File

@@ -1,200 +0,0 @@
/*
* Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
import QtQuick 2.6
import QtQuick.Dialogs 1.3
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import com.nextcloud.desktopclient 1.0 as NC
ColumnLayout {
id: rootLayout
spacing: 0
property NC.UserStatusSelectorModel userStatusSelectorModel
FontMetrics {
id: metrics
}
Text {
Layout.topMargin: 16
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.bottomMargin: 8
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
font.bold: true
text: qsTr("Online status")
}
GridLayout {
Layout.margins: 8
Layout.alignment: Qt.AlignTop
columns: 2
rows: 2
columnSpacing: 8
rowSpacing: 8
Button {
Layout.fillWidth: true
checked: NC.UserStatus.Online == userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.onlineIcon
icon.color: "transparent"
text: qsTr("Online")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Online)
implicitWidth: 100
}
Button {
Layout.fillWidth: true
checked: NC.UserStatus.Away == userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.awayIcon
icon.color: "transparent"
text: qsTr("Away")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Away)
implicitWidth: 100
}
Button {
Layout.fillWidth: true
checked: NC.UserStatus.DoNotDisturb == userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.dndIcon
icon.color: "transparent"
text: qsTr("Do not disturb")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.DoNotDisturb)
implicitWidth: 100
}
Button {
Layout.fillWidth: true
checked: NC.UserStatus.Invisible == userStatusSelectorModel.onlineStatus
checkable: true
icon.source: userStatusSelectorModel.invisibleIcon
icon.color: "transparent"
text: qsTr("Invisible")
onClicked: userStatusSelectorModel.setOnlineStatus(NC.UserStatus.Invisible)
implicitWidth: 100
}
}
Text {
Layout.topMargin: 16
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.bottomMargin: 8
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
font.bold: true
text: qsTr("Status message")
}
RowLayout {
Layout.topMargin: 8
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.bottomMargin: 16
Layout.alignment: Qt.AlignTop
Layout.fillWidth: true
Button {
Layout.preferredWidth: userStatusMessageTextField.height // metrics.height * 2
Layout.preferredHeight: userStatusMessageTextField.height // metrics.height * 2
text: userStatusSelectorModel.userStatusEmoji
onClicked: emojiDialog.open()
}
Popup {
id: emojiDialog
padding: 0
margins: 0
anchors.centerIn: Overlay.overlay
EmojiPicker {
id: emojiPicker
onChosen: {
userStatusSelectorModel.userStatusEmoji = emoji
emojiDialog.close()
}
}
}
TextField {
id: userStatusMessageTextField
Layout.fillWidth: true
placeholderText: qsTr("What is your status?")
text: userStatusSelectorModel.userStatusMessage
selectByMouse: true
onEditingFinished: userStatusSelectorModel.setUserStatusMessage(text)
}
}
Repeater {
model: userStatusSelectorModel.predefinedStatusesCount
Button {
id: control
Layout.fillWidth: true
flat: !hovered
hoverEnabled: true
text: userStatusSelectorModel.predefinedStatus(index).icon + " <b>" + userStatusSelectorModel.predefinedStatus(index).message + "</b> - " + userStatusSelectorModel.predefinedStatusClearAt(index)
onClicked: userStatusSelectorModel.setPredefinedStatus(index)
}
}
RowLayout {
Layout.topMargin: 16
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.bottomMargin: 8
Layout.alignment: Qt.AlignTop
Text {
text: qsTr("Clear status message after")
}
ComboBox {
Layout.fillWidth: true
model: userStatusSelectorModel.clearAtValues
displayText: userStatusSelectorModel.clearAt
onActivated: userStatusSelectorModel.setClearAt(index)
}
}
RowLayout {
Layout.margins: 8
Layout.alignment: Qt.AlignTop
Button {
Layout.fillWidth: true
text: qsTr("Clear status message")
onClicked: userStatusSelectorModel.clearUserStatus()
}
Button {
highlighted: true
Layout.fillWidth: true
text: qsTr("Set status message")
onClicked: userStatusSelectorModel.setUserStatus()
}
}
ErrorBox {
Layout.margins: 8
Layout.fillWidth: true
visible: userStatusSelectorModel.errorMessage != ""
text: "<b>Error:</b> " + userStatusSelectorModel.errorMessage
}
}

View File

@@ -1,27 +0,0 @@
import QtQuick.Window 2.15
import com.nextcloud.desktopclient 1.0 as NC
Window {
id: dialog
property NC.UserStatusSelectorModel model: NC.UserStatusSelectorModel {
onFinished: dialog.close()
}
minimumWidth: view.implicitWidth
minimumHeight: view.implicitHeight
maximumWidth: view.implicitWidth
maximumHeight: view.implicitHeight
width: maximumWidth
height: maximumHeight
visible: true
flags: Qt.Dialog
UserStatusSelector {
id: view
userStatusSelectorModel: model
}
}

View File

@@ -380,8 +380,6 @@ void AccountManager::deleteAccount(AccountState *account)
// Forget E2E keys // Forget E2E keys
account->account()->e2e()->forgetSensitiveData(account->account()); account->account()->e2e()->forgetSensitiveData(account->account());
account->account()->deleteAppToken();
emit accountSyncConnectionRemoved(account); emit accountSyncConnectionRemoved(account);
emit accountRemoved(account); emit accountRemoved(account);
} }

View File

@@ -28,7 +28,7 @@ class AccountManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
static AccountManager *instance(); static AccountManager *instance();
~AccountManager() override = default; ~AccountManager() = default;
/** /**
* Saves the accounts to a given settings file * Saves the accounts to a given settings file

View File

@@ -86,11 +86,11 @@ void showEnableE2eeWithVirtualFilesWarningDialog(std::function<void(void)> onAcc
const auto messageBox = new QMessageBox; const auto messageBox = new QMessageBox;
messageBox->setAttribute(Qt::WA_DeleteOnClose); messageBox->setAttribute(Qt::WA_DeleteOnClose);
messageBox->setText(AccountSettings::tr("End-to-End Encryption with Virtual Files")); messageBox->setText(AccountSettings::tr("End-to-End Encryption with Virtual Files"));
messageBox->setInformativeText(AccountSettings::tr("You seem to have the Virtual Files feature enabled on this folder. " messageBox->setInformativeText(AccountSettings::tr("You seem to have the Virtual Files feature enabled on this folder. At "
"At the moment, it is not possible to implicitly download virtual files that are " " the moment, it is not possible to implicitly download virtual files that are "
"End-to-End encrypted. To get the best experience with Virtual Files and " "End-to-End encrypted. To get the best experience with Virtual Files and"
"End-to-End Encryption, make sure the encrypted folder is marked with " " End-to-End Encryption, make sure the encrypted folder is marked with"
"\"Make always available locally\".")); " \"Make always available locally\"."));
messageBox->setIcon(QMessageBox::Warning); messageBox->setIcon(QMessageBox::Warning);
const auto dontEncryptButton = messageBox->addButton(QMessageBox::StandardButton::Cancel); const auto dontEncryptButton = messageBox->addButton(QMessageBox::StandardButton::Cancel);
Q_ASSERT(dontEncryptButton); Q_ASSERT(dontEncryptButton);
@@ -593,7 +593,6 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
ac = menu->addAction(tr("Disable virtual file support …")); ac = menu->addAction(tr("Disable virtual file support …"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotDisableVfsCurrentFolder); connect(ac, &QAction::triggered, this, &AccountSettings::slotDisableVfsCurrentFolder);
ac->setDisabled(Theme::instance()->enforceVirtualFilesSyncFolder());
} }
if (Theme::instance()->showVirtualFilesOption() if (Theme::instance()->showVirtualFilesOption()
@@ -827,9 +826,7 @@ void AccountSettings::slotEnableVfsCurrentFolder()
folder->setRootPinState(PinState::Unspecified); folder->setRootPinState(PinState::Unspecified);
for (const auto &entry : oldBlacklist) { for (const auto &entry : oldBlacklist) {
folder->journalDb()->schedulePathForRemoteDiscovery(entry); folder->journalDb()->schedulePathForRemoteDiscovery(entry);
if (!folder->vfs().setPinState(entry, PinState::OnlineOnly)) { folder->vfs().setPinState(entry, PinState::OnlineOnly);
qCWarning(lcAccountSettings) << "Could not set pin state of" << entry << "to online only";
}
} }
folder->slotNextSyncFullLocalDiscovery(); folder->slotNextSyncFullLocalDiscovery();
@@ -935,9 +932,7 @@ void AccountSettings::slotSetSubFolderAvailability(Folder *folder, const QString
Q_ASSERT(!path.endsWith('/')); Q_ASSERT(!path.endsWith('/'));
// Update the pin state on all items // Update the pin state on all items
if (!folder->vfs().setPinState(path, state)) { folder->vfs().setPinState(path, state);
qCWarning(lcAccountSettings) << "Could not set pin state of" << path << "to" << state;
}
// Trigger sync // Trigger sync
folder->schedulePathForLocalDiscovery(path); folder->schedulePathForLocalDiscovery(path);

View File

@@ -55,7 +55,7 @@ class AccountSettings : public QWidget
public: public:
explicit AccountSettings(AccountState *accountState, QWidget *parent = nullptr); explicit AccountSettings(AccountState *accountState, QWidget *parent = nullptr);
~AccountSettings() override; ~AccountSettings();
QSize sizeHint() const override { return ownCloudGui::settingsDialogSize(); } QSize sizeHint() const override { return ownCloudGui::settingsDialogSize(); }
bool canEncryptOrDecrypt(const FolderStatusModel::SubFolderInfo* folderInfo); bool canEncryptOrDecrypt(const FolderStatusModel::SubFolderInfo* folderInfo);

View File

@@ -44,6 +44,7 @@ AccountState::AccountState(AccountPtr account)
, _waitingForNewCredentials(false) , _waitingForNewCredentials(false)
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay , _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
, _remoteWipe(new RemoteWipe(_account)) , _remoteWipe(new RemoteWipe(_account))
, _userStatus(new UserStatus(this))
, _isDesktopNotificationsAllowed(true) , _isDesktopNotificationsAllowed(true)
{ {
qRegisterMetaType<AccountState *>("AccountState*"); qRegisterMetaType<AccountState *>("AccountState*");
@@ -126,6 +127,26 @@ void AccountState::setState(State state)
emit stateChanged(_state); emit stateChanged(_state);
} }
UserStatus::Status AccountState::status() const
{
return _userStatus->status();
}
QString AccountState::statusMessage() const
{
return _userStatus->message();
}
QUrl AccountState::statusIcon() const
{
return _userStatus->icon();
}
QString AccountState::statusEmoji() const
{
return _userStatus->emoji();
}
QString AccountState::stateString(State state) QString AccountState::stateString(State state)
{ {
switch (state) { switch (state) {
@@ -441,6 +462,12 @@ void AccountState::fetchNavigationApps(){
job->getNavigationApps(); job->getNavigationApps();
} }
void AccountState::fetchUserStatus()
{
connect(_userStatus, &UserStatus::fetchUserStatusFinished, this, &AccountState::statusChanged);
_userStatus->fetchUserStatus(_account);
}
void AccountState::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){ void AccountState::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
if(statusCode == 200){ if(statusCode == 200){
qCDebug(lcAccountState) << "New navigation apps ETag Response Header received " << value; qCDebug(lcAccountState) << "New navigation apps ETag Response Header received " << value;

View File

@@ -21,7 +21,7 @@
#include <QPointer> #include <QPointer>
#include "connectionvalidator.h" #include "connectionvalidator.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include "userstatus.h"
#include <memory> #include <memory>
class QSettings; class QSettings;
@@ -82,7 +82,7 @@ public:
/// Use the account as parent /// Use the account as parent
explicit AccountState(AccountPtr account); explicit AccountState(AccountPtr account);
~AccountState() override; ~AccountState();
/** Creates an account state from settings and an Account object. /** Creates an account state from settings and an Account object.
* *
@@ -162,6 +162,23 @@ public:
///Asks for user credentials ///Asks for user credentials
void handleInvalidCredentials(); void handleInvalidCredentials();
/** Returns the user status (Online, Dnd, Away, Offline, Invisible)
* https://gist.github.com/georgehrke/55a0412007f13be1551d1f9436a39675
*/
UserStatus::Status status() const;
/** Returns the user status Message (text)
*/
QString statusMessage() const;
/** Returns the user status icon url
*/
QUrl statusIcon() const;
/** Returns the user status emoji
*/
QString statusEmoji() const;
/** Returns the notifications status retrieved by the notificatons endpoint /** Returns the notifications status retrieved by the notificatons endpoint
* https://github.com/nextcloud/desktop/issues/2318#issuecomment-680698429 * https://github.com/nextcloud/desktop/issues/2318#issuecomment-680698429
*/ */
@@ -171,6 +188,10 @@ public:
*/ */
void setDesktopNotificationsAllowed(bool isAllowed); void setDesktopNotificationsAllowed(bool isAllowed);
/** Fetch the user status (status, icon, message)
*/
void fetchUserStatus();
public slots: public slots:
/// Triggers a ping to the server to update state and /// Triggers a ping to the server to update state and
/// connection status and errors. /// connection status and errors.
@@ -235,6 +256,7 @@ private:
*/ */
AccountAppList _apps; AccountAppList _apps;
UserStatus *_userStatus;
bool _isDesktopNotificationsAllowed; bool _isDesktopNotificationsAllowed;
}; };

View File

@@ -35,7 +35,7 @@ class AddCertificateDialog : public QDialog
public: public:
explicit AddCertificateDialog(QWidget *parent = nullptr); explicit AddCertificateDialog(QWidget *parent = nullptr);
~AddCertificateDialog() override; ~AddCertificateDialog();
QString getCertificatePath(); QString getCertificatePath();
QString getCertificatePasswd(); QString getCertificatePasswd();
void showErrorMessage(const QString message); void showErrorMessage(const QString message);

View File

@@ -27,14 +27,13 @@
#include "folderman.h" #include "folderman.h"
#include "logger.h" #include "logger.h"
#include "configfile.h" #include "configfile.h"
#include "socketapi/socketapi.h" #include "socketapi.h"
#include "sslerrordialog.h" #include "sslerrordialog.h"
#include "theme.h" #include "theme.h"
#include "clientproxy.h" #include "clientproxy.h"
#include "sharedialog.h" #include "sharedialog.h"
#include "accountmanager.h" #include "accountmanager.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include "pushnotifications.h"
#if defined(BUILD_UPDATER) #if defined(BUILD_UPDATER)
#include "updater/ocupdater.h" #include "updater/ocupdater.h"
@@ -179,7 +178,7 @@ Application::Application(int &argc, char **argv)
, _showLogWindow(false) , _showLogWindow(false)
, _logExpire(0) , _logExpire(0)
, _logFlush(false) , _logFlush(false)
, _logDebug(true) , _logDebug(false)
, _userTriggeredConnect(false) , _userTriggeredConnect(false)
, _debugMode(false) , _debugMode(false)
, _backgroundMode(false) , _backgroundMode(false)
@@ -350,9 +349,6 @@ Application::Application(int &argc, char **argv)
connect(FolderMan::instance()->socketApi(), &SocketApi::shareCommandReceived, connect(FolderMan::instance()->socketApi(), &SocketApi::shareCommandReceived,
_gui.data(), &ownCloudGui::slotShowShareDialog); _gui.data(), &ownCloudGui::slotShowShareDialog);
connect(FolderMan::instance()->socketApi(), &SocketApi::fileActivityCommandReceived,
Systray::instance(), &Systray::showFileActivityDialog);
// startup procedure. // startup procedure.
connect(&_checkConnectionTimer, &QTimer::timeout, this, &Application::slotCheckConnection); connect(&_checkConnectionTimer, &QTimer::timeout, this, &Application::slotCheckConnection);
_checkConnectionTimer.setInterval(ConnectionValidator::DefaultCallingIntervalMsec); // check for connection every 32 seconds. _checkConnectionTimer.setInterval(ConnectionValidator::DefaultCallingIntervalMsec); // check for connection every 32 seconds.
@@ -460,10 +456,9 @@ void Application::slotCheckConnection()
// Don't check if we're manually signed out or // Don't check if we're manually signed out or
// when the error is permanent. // when the error is permanent.
const auto pushNotifications = accountState->account()->pushNotifications(); if (state != AccountState::SignedOut
const auto pushNotificationsAvailable = (pushNotifications && pushNotifications->isReady()); && state != AccountState::ConfigurationError
if (state != AccountState::SignedOut && state != AccountState::ConfigurationError && state != AccountState::AskingCredentials) {
&& state != AccountState::AskingCredentials && !pushNotificationsAvailable) {
accountState->checkConnectivity(); accountState->checkConnectivity();
} }
} }
@@ -483,6 +478,7 @@ void Application::slotCrash()
void Application::slotownCloudWizardDone(int res) void Application::slotownCloudWizardDone(int res)
{ {
AccountManager *accountMan = AccountManager::instance();
FolderMan *folderMan = FolderMan::instance(); FolderMan *folderMan = FolderMan::instance();
// During the wizard, scheduling of new syncs is disabled // During the wizard, scheduling of new syncs is disabled
@@ -495,7 +491,7 @@ void Application::slotownCloudWizardDone(int res)
// If one account is configured: enable autostart // If one account is configured: enable autostart
#ifndef QT_DEBUG #ifndef QT_DEBUG
bool shouldSetAutoStart = AccountManager::instance()->accounts().size() == 1; bool shouldSetAutoStart = (accountMan->accounts().size() == 1);
#else #else
bool shouldSetAutoStart = false; bool shouldSetAutoStart = false;
#endif #endif
@@ -529,12 +525,7 @@ void Application::setupLogging()
logger->enterNextLogFile(); logger->enterNextLogFile();
qCInfo(lcApplication) << "##################" << _theme->appName() qCInfo(lcApplication) << QString::fromLatin1("################## %1 locale:[%2] ui_lang:[%3] version:[%4] os:[%5]").arg(_theme->appName()).arg(QLocale::system().name()).arg(property("ui_lang").toString()).arg(_theme->version()).arg(Utility::platformName());
<< "locale:" << QLocale::system().name()
<< "ui_lang:" << property("ui_lang")
<< "version:" << _theme->version()
<< "os:" << Utility::platformName();
qCInfo(lcApplication) << "Arguments:" << qApp->arguments();
} }
void Application::slotUseMonoIconsChanged(bool) void Application::slotUseMonoIconsChanged(bool)

View File

@@ -57,7 +57,7 @@ class Application : public SharedTools::QtSingleApplication
Q_OBJECT Q_OBJECT
public: public:
explicit Application(int &argc, char **argv); explicit Application(int &argc, char **argv);
~Application() override; ~Application();
bool giveHelp(); bool giveHelp();
void showHelp(); void showHelp();
@@ -88,7 +88,7 @@ protected:
void parseOptions(const QStringList &); void parseOptions(const QStringList &);
void setupTranslations(); void setupTranslations();
void setupLogging(); void setupLogging();
bool event(QEvent *event) override; bool event(QEvent *event);
signals: signals:
void folderRemoved(); void folderRemoved();

View File

@@ -29,7 +29,7 @@ AuthenticationDialog::AuthenticationDialog(const QString &realm, const QString &
{ {
setWindowTitle(tr("Authentication Required")); setWindowTitle(tr("Authentication Required"));
auto *lay = new QVBoxLayout(this); auto *lay = new QVBoxLayout(this);
auto *label = new QLabel(tr("Enter username and password for \"%1\" at %2.").arg(realm, domain)); auto *label = new QLabel(tr("Enter username and password for '%1' at %2.").arg(realm, domain));
label->setTextFormat(Qt::PlainText); label->setTextFormat(Qt::PlainText);
lay->addWidget(label); lay->addWidget(label);

View File

@@ -119,7 +119,7 @@ void CloudProviderWrapper::slotUpdateProgress(const QString &folder, const Progr
// Build status details text // Build status details text
QString msg; QString msg;
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) { if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
msg = tr("Checking for changes in \"%1\"").arg(progress._currentDiscoveredRemoteFolder); msg = tr("Checking for changes in '%1'").arg(progress._currentDiscoveredRemoteFolder);
} else if (progress.totalSize() == 0) { } else if (progress.totalSize() == 0) {
qint64 currentFile = progress.currentFile(); qint64 currentFile = progress.currentFile();
qint64 totalFileCount = qMax(progress.totalFiles(), currentFile); qint64 totalFileCount = qMax(progress.totalFiles(), currentFile);

View File

@@ -39,7 +39,7 @@ class CloudProviderWrapper : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit CloudProviderWrapper(QObject *parent = nullptr, Folder *folder = nullptr, int folderId = 0, CloudProvidersProviderExporter* cloudprovider = nullptr); explicit CloudProviderWrapper(QObject *parent = nullptr, Folder *folder = nullptr, int folderId = 0, CloudProvidersProviderExporter* cloudprovider = nullptr);
~CloudProviderWrapper() override; ~CloudProviderWrapper();
CloudProvidersAccountExporter* accountExporter(); CloudProvidersAccountExporter* accountExporter();
Folder* folder(); Folder* folder();
GMenuModel* getMenuModel(); GMenuModel* getMenuModel();

View File

@@ -100,7 +100,7 @@ void Flow2Auth::fetchNewToken(const TokenAction action)
pollToken = json.value("poll").toObject().value("token").toString(); pollToken = json.value("poll").toObject().value("token").toString();
pollEndpoint = json.value("poll").toObject().value("endpoint").toString(); pollEndpoint = json.value("poll").toObject().value("endpoint").toString();
if (_enforceHttps && QUrl(pollEndpoint).scheme() != QStringLiteral("https")) { if (_enforceHttps && QUrl(pollEndpoint).scheme() != QStringLiteral("https")) {
qCWarning(lcFlow2auth) << "Can not poll endpoint because the returned url" << pollEndpoint << "does not start with https"; qCWarning(lcFlow2auth) << "Can not poll endpoint because the returned url" << _pollEndpoint << "does not start with https";
emit result(Error, tr("The polling URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator.")); emit result(Error, tr("The polling URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator."));
return; return;
} }
@@ -115,7 +115,7 @@ void Flow2Auth::fetchNewToken(const TokenAction action)
errorReason = tr("Error returned from the server: <em>%1</em>") errorReason = tr("Error returned from the server: <em>%1</em>")
.arg(errorFromJson.toHtmlEscaped()); .arg(errorFromJson.toHtmlEscaped());
} else if (reply->error() != QNetworkReply::NoError) { } else if (reply->error() != QNetworkReply::NoError) {
errorReason = tr("There was an error accessing the \"token\" endpoint: <br><em>%1</em>") errorReason = tr("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
.arg(reply->errorString().toHtmlEscaped()); .arg(reply->errorString().toHtmlEscaped());
} else if (jsonParseError.error != QJsonParseError::NoError) { } else if (jsonParseError.error != QJsonParseError::NoError) {
errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>") errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>")
@@ -223,7 +223,7 @@ void Flow2Auth::slotPollTimerTimeout()
errorReason = tr("Error returned from the server: <em>%1</em>") errorReason = tr("Error returned from the server: <em>%1</em>")
.arg(errorFromJson.toHtmlEscaped()); .arg(errorFromJson.toHtmlEscaped());
} else if (reply->error() != QNetworkReply::NoError) { } else if (reply->error() != QNetworkReply::NoError) {
errorReason = tr("There was an error accessing the \"token\" endpoint: <br><em>%1</em>") errorReason = tr("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
.arg(reply->errorString().toHtmlEscaped()); .arg(reply->errorString().toHtmlEscaped());
} else if (jsonParseError.error != QJsonParseError::NoError) { } else if (jsonParseError.error != QJsonParseError::NoError) {
errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>") errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>")

View File

@@ -42,7 +42,7 @@ public:
}; };
Flow2Auth(Account *account, QObject *parent); Flow2Auth(Account *account, QObject *parent);
~Flow2Auth() override; ~Flow2Auth();
enum Result { NotSupported, enum Result { NotSupported,
LoggedIn, LoggedIn,

View File

@@ -108,7 +108,7 @@ void HttpCredentialsGui::showDialog()
} }
if (!_fetchErrorString.isEmpty()) { if (!_fetchErrorString.isEmpty()) {
msg += QLatin1String("<br>") msg += QLatin1String("<br>")
+ tr("Reading from keychain failed with error: \"%1\"") + tr("Reading from keychain failed with error: '%1'")
.arg(Utility::escape(_fetchErrorString)) .arg(Utility::escape(_fetchErrorString))
+ QLatin1String("<br>"); + QLatin1String("<br>");
} }

View File

@@ -70,14 +70,13 @@ void OAuth::start()
QByteArray peek = socket->peek(qMin(socket->bytesAvailable(), 4000LL)); //The code should always be within the first 4K QByteArray peek = socket->peek(qMin(socket->bytesAvailable(), 4000LL)); //The code should always be within the first 4K
if (peek.indexOf('\n') < 0) if (peek.indexOf('\n') < 0)
return; // wait until we find a \n return; // wait until we find a \n
const QRegularExpression rx("^GET /\\?code=([a-zA-Z0-9]+)[& ]"); // Match a /?code=... URL QRegExp rx("^GET /\\?code=([a-zA-Z0-9]+)[& ]"); // Match a /?code=... URL
const auto rxMatch = rx.match(peek); if (rx.indexIn(peek) != 0) {
if (!rxMatch.hasMatch()) {
httpReplyAndClose(socket, "404 Not Found", "<html><head><title>404 Not Found</title></head><body><center><h1>404 Not Found</h1></center></body></html>"); httpReplyAndClose(socket, "404 Not Found", "<html><head><title>404 Not Found</title></head><body><center><h1>404 Not Found</h1></center></body></html>");
return; return;
} }
QString code = rxMatch.captured(1); // The 'code' is the first capture of the regexp QString code = rx.cap(1); // The 'code' is the first capture of the regexp
QUrl requestToken = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/apps/oauth2/api/v1/token")); QUrl requestToken = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/apps/oauth2/api/v1/token"));
QNetworkRequest req; QNetworkRequest req;

View File

@@ -47,7 +47,7 @@ public:
, _account(account) , _account(account)
{ {
} }
~OAuth() override; ~OAuth();
enum Result { NotSupported, enum Result { NotSupported,
LoggedIn, LoggedIn,

File diff suppressed because it is too large Load Diff

View File

@@ -1,137 +0,0 @@
/*
* Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#pragma once
#include <QObject>
#include <QSettings>
#include <QObject>
#include <QQmlEngine>
#include <QVariant>
#include <QVector>
#include <QAbstractItemModel>
namespace OCC {
struct Emoji
{
Emoji(QString u, QString s, bool isCustom = false)
: unicode(std::move(std::move(u)))
, shortname(std::move(std::move(s)))
, isCustom(isCustom)
{
}
Emoji() = default;
friend QDataStream &operator<<(QDataStream &arch, const Emoji &object)
{
arch << object.unicode;
arch << object.shortname;
return arch;
}
friend QDataStream &operator>>(QDataStream &arch, Emoji &object)
{
arch >> object.unicode;
arch >> object.shortname;
object.isCustom = object.unicode.startsWith("image://");
return arch;
}
QString unicode;
QString shortname;
bool isCustom = false;
Q_GADGET
Q_PROPERTY(QString unicode MEMBER unicode)
Q_PROPERTY(QString shortname MEMBER shortname)
Q_PROPERTY(bool isCustom MEMBER isCustom)
};
class EmojiCategoriesModel : public QAbstractListModel
{
public:
QVariant data(const QModelIndex &index, int role) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
private:
enum Roles {
EmojiRole = 0,
LabelRole
};
struct Category
{
QString emoji;
QString label;
};
static const std::vector<Category> categories;
};
class EmojiModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList model READ model NOTIFY modelChanged)
Q_PROPERTY(QAbstractListModel *emojiCategoriesModel READ emojiCategoriesModel CONSTANT)
Q_PROPERTY(QVariantList history READ history NOTIFY historyChanged)
Q_PROPERTY(QVariantList people MEMBER people CONSTANT)
Q_PROPERTY(QVariantList nature MEMBER nature CONSTANT)
Q_PROPERTY(QVariantList food MEMBER food CONSTANT)
Q_PROPERTY(QVariantList activity MEMBER activity CONSTANT)
Q_PROPERTY(QVariantList travel MEMBER travel CONSTANT)
Q_PROPERTY(QVariantList objects MEMBER objects CONSTANT)
Q_PROPERTY(QVariantList symbols MEMBER symbols CONSTANT)
Q_PROPERTY(QVariantList flags MEMBER flags CONSTANT)
public:
explicit EmojiModel(QObject *parent = nullptr)
: QObject(parent)
{
}
Q_INVOKABLE QVariantList history() const;
Q_INVOKABLE void setCategory(const QString &category);
Q_INVOKABLE void emojiUsed(const QVariant &modelData);
QVariantList model() const;
QAbstractListModel *emojiCategoriesModel();
signals:
void historyChanged();
void modelChanged();
private:
static const QVariantList people;
static const QVariantList nature;
static const QVariantList food;
static const QVariantList activity;
static const QVariantList travel;
static const QVariantList objects;
static const QVariantList symbols;
static const QVariantList flags;
QSettings _settings;
QString _category = "history";
EmojiCategoriesModel _emojiCategoriesModel;
};
}
Q_DECLARE_METATYPE(OCC::Emoji)

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) by Felix Weilbach <felix.weilbach@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "fileactivitylistmodel.h"
#include "folderman.h"
#include "tray/activitylistmodel.h"
namespace OCC {
Q_LOGGING_CATEGORY(lcFileActivityListModel, "nextcloud.gui.fileactivitylistmodel", QtInfoMsg)
FileActivityListModel::FileActivityListModel(QObject *parent)
: ActivityListModel(nullptr, parent)
{
setDisplayActions(false);
}
void FileActivityListModel::load(AccountState *accountState, const QString &localPath)
{
Q_ASSERT(accountState);
if (!accountState || currentlyFetching()) {
return;
}
setAccountState(accountState);
const auto folder = FolderMan::instance()->folderForPath(localPath);
if (!folder) {
return;
}
const auto file = folder->fileFromLocalPath(localPath);
SyncJournalFileRecord fileRecord;
if (!folder->journalDb()->getFileRecord(file, &fileRecord) || !fileRecord.isValid()) {
return;
}
_fileId = fileRecord._fileId;
slotRefreshActivity();
}
void FileActivityListModel::startFetchJob()
{
if (!accountState()->isConnected()) {
return;
}
setCurrentlyFetching(true);
const QString url(QStringLiteral("ocs/v2.php/apps/activity/api/v2/activity/filter"));
auto job = new JsonApiJob(accountState()->account(), url, this);
QObject::connect(job, &JsonApiJob::jsonReceived,
this, &FileActivityListModel::activitiesReceived);
QUrlQuery params;
params.addQueryItem(QStringLiteral("sort"), QStringLiteral("asc"));
params.addQueryItem(QStringLiteral("object_type"), "files");
params.addQueryItem(QStringLiteral("object_id"), _fileId);
job->addQueryParams(params);
setDoneFetching(true);
setHideOldActivities(true);
job->start();
}
}

Some files were not shown because too many files have changed in this diff Show More