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

Compare commits

...

72 Commits

Author SHA1 Message Date
Markus Goetz
2d38703898 VERSION.cmake: 2.4.2-rc1 2018-07-06 09:36:29 +02:00
Markus Goetz
f283c0c59c ChangeLog: 2.4.2 additions 2018-07-05 18:55:04 +02:00
Christian Kamm
0d83d7cb68 Log: Adjust update/reconcile log verbosity
Not having these enabled by default is causing significant extra back
and forth with reporters since they must manually use --logdebug for the
log to be useful.

(cherry picked from commit 25cca051a9)
2018-07-05 17:34:07 +02:00
Olivier Goffart
2e10cec2cb Reconcile: When detecting a local move, keep the local mtime
https://github.com/owncloud/client/issues/6629#issuecomment-402450691
(cherry picked from commit 90ec9a9735)
2018-07-05 17:32:11 +02:00
Thomas Boerger
3802131bad Drop Jenkinsfile, replaced by DroneCI
So far DroneCI is showing stable results, that's the point in time where
we can get rid of Jenkins 💣
2018-07-05 13:44:40 +02:00
Markus Goetz
5467950f62 MSI: Always with logfile #6609 2018-06-26 13:39:23 +02:00
Markus Goetz
3ba5bb52f3 OCUpdater: Fix missing return 2018-06-20 13:36:05 +02:00
Markus Goetz
5c011c5c21 ChangeLog: 2.4.2 2018-06-20 12:32:28 +02:00
Markus Goetz
532e975687 GeneralSettings: Hide update channel for other themes
For #6585

(cherry picked from commit e1a4c3ab72)
2018-06-20 12:30:25 +02:00
Olivier Goffart
7efc3220f4 OAuth2: Try to refresh the token even if the credentials weren't ready.
This can happen when the client is started and the internet connection
was not enabled. Then we would fetch the credentials, but we would
no do the refresh token step (because network is down).
So next time we try to connect, we would also not refresh the token
because the credentials are not marked as 'ready'

Reported in
https://github.com/owncloud/client/issues/6522#issuecomment-396845167

(cherry picked from commit 4cc0539080)
2018-06-20 12:27:57 +02:00
Christian Kamm
b5444def55 Tray workarounds backport for 2.4 #6545
* Disentangle the previous 'qdbusWorkarounds' into three different
  things
* Make not trusting tray.isVisible() a new workaround
* Introduce env vars for all workaround flags
* Use the workaround flags for OSX
* Determine workaround flags for KDE when the plasma integration plugin
  is missing

(cherry picked from commit 99116acdca)
(cherry picked from commit ca033b9685)
(cherry picked from commit 8b1d9799a3)
(cherry picked from commit a0d6139505)
2018-06-19 18:22:34 +02:00
Dominik Schmidt
c7ba898fe0 Implement startDetached() via QProcess::startDetached on non windows 2018-06-19 18:18:25 +02:00
Dominik Schmidt
7a8c8b19c2 Remove anonymous namespace 2018-06-19 18:18:25 +02:00
Dominik Schmidt
72c9d207a0 Workaround bug in Qt 5.6 that makes QProcess::startDetached always launch a console window 2018-06-19 18:18:25 +02:00
Dominik Schmidt
1e4727cfec Extract filename of updateFile without leading slash 2018-06-19 18:18:25 +02:00
Dominik Schmidt
8237c5be69 Escape msi and owncloud.exe path (who knows...) 2018-06-19 18:18:25 +02:00
Dominik Schmidt
63877d5293 Run msi properly and restart client after update 2018-06-19 18:18:25 +02:00
Dominik Schmidt
737353a017 Implement basic .msi support in updater 2018-06-19 18:18:25 +02:00
Olivier Goffart
528b5e3108 Updater: Fix beta channel for translated clients.
The names in the combobox are being translated, so we need to rely
on the index rather than the text.

(cherry picked from commit ae80317a74)
2018-06-19 12:57:28 +02:00
Christian Kamm
5d098140e7 Settings: Add warning when switching update channel
(cherry picked from commit 53f52b4cf5)
2018-05-24 13:39:00 +02:00
Christian Kamm
aeb4eed7b5 Updater: Make sparkle updater respect release channel
(cherry picked from commit 293c2b4f79)
2018-05-24 13:39:00 +02:00
Markus Goetz
c68b112858 Auto Updater: Show UI element also on macOS
(cherry picked from commit dfdc2e1e87f99d387a042f4983c999fbb7fcf3d9)
(cherry picked from commit 29349d4b3a)
2018-05-24 13:39:00 +02:00
Christian Kamm
b4f2c3c369 Settings: Add update channel combobox #6259
(cherry picked from commit 7790953a2c)

Significant conflicts in:
	src/gui/updater/updater.cpp
2018-05-24 13:39:00 +02:00
Olivier Goffart
084f522de1 Credentials: Retry fetching from the keychain in case the keychain is still starting
When owncloud is restored, at boot time, it might be started before the
crendential manager. So if we detect an error, wait 10 seconds and hopefully
it'd be loaded by then.

Issues: #4274, #6522
(cherry picked from commit c625d8e3b7)
2018-05-24 12:41:17 +02:00
Markus Goetz
5d5e0220b4 macOS: Don't use WAL for sqlite3 in /Volumes
For #6049

(cherry picked from commit 309c53ca8f)
2018-05-17 13:21:24 +02:00
Christian Kamm
7b5ce24302 Upload: Adjust timeout for final job based on size #6527
Some servers have virus scanners and the like that can delay the
response of the final chunked upload assembly significantly, often
breaking the current 5min (!) timeout. See owncloud/enterprise#2480
for details.

(cherry picked from commit 2638332dc6)
2018-05-17 13:15:51 +02:00
Christian Kamm
19e33d0924 SyncJournal: Check file existence even for open dbs #6049
With WAL mode sqlite seems to occasionally crash when the
underlying filesystem goes away.

(cherry picked from commit b1224cff0c)
2018-05-17 13:13:31 +02:00
Olivier Goffart
f8a4994307 Nautilus: Fix Python3 and remove many debug
Use b'\n' in the call to rfind, as the _remainder is bytes, not a string.

Remove most of the debug message which happens during normal operation.
They are mostly spamming the nautilus console, and can also cause bug
as they may throw exception in case of wrong encoding.

Relates to issue: #6406

(cherry picked from commit 1ab3a9fc13)
2018-04-26 10:18:37 +02:00
Christian Kamm
04fb952814 Nautilus shell integration: Print python version on startup #6406
(cherry picked from commit 44071f0892)
2018-04-26 10:18:37 +02:00
Christian Kamm
8d6e9523bb Nautilus integration: Not a ColumnProvider
The nautilus plugin doesn't actually define get_columns(), so pretending
to be a ColumnProvider lead to a critical warning on startup.

(cherry picked from commit 9f346037ee)
2018-04-26 10:18:37 +02:00
Thomas Boerger
b317cc18d0 Dropped .travis.yml from repo 2018-04-24 12:53:13 +02:00
Thomas Boerger
03a5833e29 Build clang and gcc on drone 2018-04-24 12:53:13 +02:00
Markus Goetz
91a9c65173 macOS: Unload the Finder extension on exit #5382 #3819
(cherry picked from commit 930053449184a3204525ba5d1e307b6629f0b925)
2018-04-11 13:40:51 +02:00
Markus Goetz
edabed9594 macdeployqt: Adjust minimum version based on our Qt #5932
(cherry picked from commit e9646364a0)
2018-04-03 21:31:51 +02:00
Olivier Goffart
838beded20 csync_update: add the checksum in the discovery log
Issue #6414

(cherry picked from commit 39d909b05a)
2018-04-03 15:17:15 +02:00
Christian Kamm
7dcfe9993c Blacklisting must prevent parent etag updates #6411
(cherry picked from commit 5e75d224ee)
2018-03-28 10:02:46 +02:00
Olivier Goffart
b73e2fbdab Folder: normalize the local path.
We otherwise normalize all path in the C form, so we must have
the Folder's path normalized the same. Or all comparizon will fail
(such as knowing if a file from the SocketAPI or the FilesystemWatcher
are part of the folder)

Issue #4424

(cherry picked from commit 26b991c0c0)
2018-03-27 10:56:14 +02:00
Olivier Goffart
d49771b43a propagateuploadv1: don't finalize after a done()
Should fix an assert when "Server does not support X-OC-MTime"
(Which only happens with owncloud 5)

Issue #6403

(cherry picked from commit 3f4d504c34)
2018-03-27 10:56:10 +02:00
Markus Goetz
928cdf4f4f SslButton: Add HTTP/2 info #3146
(cherry picked from commit 7739157bfc)
2018-03-27 09:02:29 +02:00
Markus Goetz
8da6fc40a1 macdeployqt: Qt 5.10.1 #5932
(cherry picked from commit 20bd943a87)
2018-03-27 08:49:57 +02:00
Markus Goetz
6e84a8d420 macOS: Put Qt version in .pkg name
(cherry picked from commit b34878c16d)
2018-03-26 19:41:46 +02:00
Christian Kamm
29557ea550 Fix nautilus/nemo shell integration encoding issues #6393
The problem was that plain encode()/decode() in python2 use ascii
encoding, not utf8.
2018-03-21 11:25:37 +01:00
Jenkins for ownCloud
37a93dca63 [tx-robot] updated from transifex 2018-03-21 02:18:33 +01:00
Jenkins for ownCloud
b632b7e0fa [tx-robot] updated from transifex 2018-03-20 02:18:30 +01:00
Jenkins for ownCloud
fc8e3b0914 [tx-robot] updated from transifex 2018-03-19 02:18:32 +01:00
Jenkins for ownCloud
861d777899 [tx-robot] updated from transifex 2018-03-18 02:18:31 +01:00
Jenkins for ownCloud
ff3e3ce886 [tx-robot] updated from transifex 2018-03-17 02:18:31 +01:00
Dominik Schmidt
567f7eb205 Apply branding to crashreporter resources file 2018-03-16 16:35:49 +01:00
Jenkins for ownCloud
c3c8ab85ec [tx-robot] updated from transifex 2018-03-16 02:18:30 +01:00
Jenkins for ownCloud
d1c887d754 [tx-robot] updated from transifex 2018-03-15 02:18:32 +01:00
Jenkins for ownCloud
991f4faafb [tx-robot] updated from transifex 2018-03-14 02:18:31 +01:00
Jenkins for ownCloud
371acb296d [tx-robot] updated from transifex 2018-03-13 02:18:36 +01:00
Jenkins for ownCloud
1119bcf539 [tx-robot] updated from transifex 2018-03-11 02:18:36 +01:00
Jenkins for ownCloud
d67018311f [tx-robot] updated from transifex 2018-03-10 02:18:34 +01:00
Jenkins for ownCloud
eaecec418e [tx-robot] updated from transifex 2018-03-09 02:18:35 +01:00
Jenkins for ownCloud
ab27bcacdf [tx-robot] updated from transifex 2018-03-08 02:18:36 +01:00
Jenkins for ownCloud
536a051460 [tx-robot] updated from transifex 2018-03-07 02:18:36 +01:00
Jenkins for ownCloud
259a117db5 [tx-robot] updated from transifex 2018-03-06 02:18:36 +01:00
Jenkins for ownCloud
167939a8c9 [tx-robot] updated from transifex 2018-03-05 02:18:37 +01:00
Jenkins for ownCloud
41ebfb635e [tx-robot] updated from transifex 2018-03-04 02:18:36 +01:00
Jenkins for ownCloud
017b8e9de3 [tx-robot] updated from transifex 2018-03-03 02:18:35 +01:00
Jenkins for ownCloud
6453c57979 [tx-robot] updated from transifex 2018-03-02 02:18:36 +01:00
Jenkins for ownCloud
a01c73be19 [tx-robot] updated from transifex 2018-03-01 02:18:37 +01:00
Jenkins for ownCloud
f63737ecb0 [tx-robot] updated from transifex 2018-02-28 02:18:35 +01:00
Jenkins for ownCloud
dd87799a82 [tx-robot] updated from transifex 2018-02-27 02:19:02 +01:00
Jenkins for ownCloud
da6b515bfc [tx-robot] updated from transifex 2018-02-26 02:19:12 +01:00
Jenkins for ownCloud
f9a03fa288 [tx-robot] updated from transifex 2018-02-25 02:19:29 +01:00
Jenkins for ownCloud
a5c66cf289 [tx-robot] updated from transifex 2018-02-24 02:18:36 +01:00
Jenkins for ownCloud
41b908e293 [tx-robot] updated from transifex 2018-02-23 02:18:35 +01:00
Jenkins for ownCloud
6ffed87b08 [tx-robot] updated from transifex 2018-02-22 02:18:34 +01:00
Jenkins for ownCloud
bd5ea43547 [tx-robot] updated from transifex 2018-02-21 02:18:51 +01:00
Markus Goetz
8ba27cb0f1 VERSION.cmake: This is 2.4.2 now 2018-02-20 12:13:58 +01:00
56 changed files with 996 additions and 415 deletions

91
.drone.yml Normal file
View File

@@ -0,0 +1,91 @@
#
# We are building GCC with make and Clang with ninja, the combinations are more
# or less arbitrarily chosen. We just want to check that both compilers and both
# CMake generators work. It's unlikely that a specific generator only breaks
# with a specific compiler.
#
workspace:
base: /drone
path: src/github.com/owncloud/client
branches:
- master
- 2.4
clone:
git:
image: plugins/git
pull: true
tags: false
pipeline:
prepare-clang:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- mkdir clang-build
- cd clang-build
- cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
building-clang:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- cd clang-build
- ninja -j4
testing-clang:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- cd clang-build
- useradd -m -s /bin/bash tester
- chown -R tester:tester .
- su-exec tester ctest --output-on-failure
prepare-gcc:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- mkdir gcc-build
- cd gcc-build
- cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
building-gcc:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- cd gcc-build
- make -j4
testing-gcc:
image: owncloudci/client:latest
pull: true
environment:
- LC_ALL=C.UTF-8
commands:
- cd gcc-build
- useradd -m -s /bin/bash tester
- chown -R tester:tester .
- su-exec tester ctest --output-on-failure
notify-slack:
image: plugins/slack
pull: true
secrets: [ slack_webhook ]
channel: desktop
when:
local: false
status: [ changed, failure ]
event: [ push ]

View File

@@ -1,37 +0,0 @@
sudo: required
language: cpp
services:
- docker
branches:
only:
- coverity_scan
before_install:
- sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
- sudo sh -c "echo 'deb-src http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
- wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Ubuntu_14.04/Release.key
- sudo apt-key add - < Release.key
- sudo apt-get update
- sudo apt-get -y build-dep owncloud-client
- checkout=$(git show-ref --head --hash head)
- cd ../
- wget https://scan.coverity.com/download/linux-64 --post-data "token=$token&project=owncloud%2Fmirall" -O coverity_tool.tgz
- mkdir coverity
- tar -xvf coverity_tool.tgz -C coverity --strip-components=1
- export PATH=$PATH:$PWD/coverity/bin/
- cd $TRAVIS_BUILD_DIR
install:
- cd ../
- mkdir client-build
- cd client-build
- cmake -DCMAKE_BUILD_TYPE="Debug" $TRAVIS_BUILD_DIR
- cov-build --dir cov-int make
- tar czvf client.tgz cov-int
- curl --form token=$token --form email=lukas@statuscode.ch --form file=@$PWD/client.tgz --form version="$checkout" --form description="$checkout" https://scan.coverity.com/builds?project=owncloud%2Fmirall
# Hack to stop processing
script: true

View File

@@ -1,6 +1,23 @@
ChangeLog ChangeLog
========= =========
version 2.4.2 (2018-06-xx)
* Linux: Tray workarounds (#6545)
* Fix nautilus/nemo shell issues (#6393, #6406)
* Updater: Add update channel feature (#6259)
* Updater: Support EXE->MSI upgrade
* SyncJournal: Fixes for sync folders on removable media (#6049, #6049)
* SslButton: Add HTTP/2 info (#3146)
* Fix assert when using ownCloud server 5 (which you should not) (#6403)
* Normalize local path (#4424)
* Blacklisting must prevent parent etag updates (#6411)
* macdeployqt: Adjust minimum version based on our Qt (#5932)
* macOS: Unload the Finder extension on exit (#5382, #3819)
* Upload: Adjust timeout for final job based on file size (#6527)
* Sync: When detecting a local move, keep the local mtime (#6629)
* Credentials: Retry fetching from the keychain in case the keychain is still starting (#4274, #6522)
* OAuth2: Try to refresh the token even if the credentials weren't ready (#6522)
version 2.4.1 (2018-02-xx) version 2.4.1 (2018-02-xx)
* Ignore files with file names that can't be encoded for the filesystem (#6287, #5676, #5719) * Ignore files with file names that can't be encoded for the filesystem (#6287, #5676, #5719)
* Issues: Speed up insertion and add hard upper limit (#6272) * Issues: Speed up insertion and add hard upper limit (#6272)

51
Jenkinsfile vendored
View File

@@ -1,51 +0,0 @@
#!groovy
//
// We now run the tests in Debug mode so that ASSERTs are triggered.
// Ideally we should run the tests in both Debug and Release so we catch
// all possible error combinations.
// See also the top comment in syncenginetestutils.h
//
node('CLIENT') {
stage 'Checkout'
checkout scm
sh '''git submodule update --init'''
stage 'Qt5'
sh '''rm -rf build
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 -DWITH_TESTING=1 -DCMAKE_PREFIX_PATH=/var/lib/jenkins/qt/5.6.2 ..
make -j4
ctest -V --output-on-failure'''
stage 'Qt5 - clang'
sh '''rm -rf build
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DCMAKE_PREFIX_PATH=/var/lib/jenkins/qt/5.6.2 ..
make -j4
ctest -V --output-on-failure'''
stage 'Win32'
def win32 = docker.image('guruz/docker-owncloud-client-win32:latest')
win32.pull() // make sure we have the latest available from Docker Hub
win32.inside {
sh '''
rm -rf build-win32
mkdir build-win32
cd build-win32
../admin/win/download_runtimes.sh
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
make -j4
make package
ctest .
'''
}
// Stage 'macOS' TODO
}

View File

@@ -19,4 +19,4 @@ set( MAC_INSTALLER_BACKGROUND_FILE "${CMAKE_SOURCE_DIR}/admin/osx/installer-back
option( WITH_CRASHREPORTER "Build crashreporter" OFF ) option( WITH_CRASHREPORTER "Build crashreporter" OFF )
set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE string "URL for crash reporter" ) set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE string "URL for crash reporter" )
set( CRASHREPORTER_ICON ":/owncloud-icon.png" )

View File

@@ -1,6 +1,6 @@
# ownCloud Desktop Client # ownCloud Desktop Client
[![Build Status](https://jenkins.owncloud.org/buildStatus/icon?job=owncloud-client/client/master)](https://jenkins.owncloud.org/job/owncloud-client/job/client/job/master/) [![Build Status](https://drone.owncloud.com/api/badges/owncloud/client/status.svg)](https://drone.owncloud.com/owncloud/client)
## Introduction ## Introduction

View File

@@ -1,11 +1,11 @@
set( MIRALL_VERSION_MAJOR 2 ) set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 4 ) set( MIRALL_VERSION_MINOR 4 )
set( MIRALL_VERSION_PATCH 1 ) set( MIRALL_VERSION_PATCH 2 )
set( MIRALL_VERSION_YEAR 2017 ) set( MIRALL_VERSION_YEAR 2018 )
set( MIRALL_SOVERSION 0 ) set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX ) if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "git") #e.g. beta1, beta2, rc1 set( MIRALL_VERSION_SUFFIX "rc1") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX ) endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD ) if( NOT DEFINED MIRALL_VERSION_BUILD )

View File

@@ -11,6 +11,7 @@ else()
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0") set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0")
endif() endif()
find_package(Qt5 5.6 COMPONENTS Core REQUIRED)
configure_file(create_mac_pkg.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh) configure_file(create_mac_pkg.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh)
configure_file(macosx.pkgproj ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj) configure_file(macosx.pkgproj ${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

@@ -23,7 +23,7 @@ identity="$3"
prjfile=$build_path/admin/osx/macosx.pkgproj prjfile=$build_path/admin/osx/macosx.pkgproj
# The name of the installer package # The name of the installer package
installer="@APPLICATION_SHORTNAME@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@" installer="@APPLICATION_SHORTNAME@-qt@Qt5Core_VERSION@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@"
installer_file="$installer.pkg" installer_file="$installer.pkg"
installer_file_tar="$installer.pkg.tar" installer_file_tar="$installer.pkg.tar"
installer_file_tar_bz2="$installer.pkg.tar.bz2" installer_file_tar_bz2="$installer.pkg.tar.bz2"

View File

@@ -22,6 +22,7 @@ import subprocess
import commands import commands
import sys import sys
from glob import glob from glob import glob
from distutils.version import LooseVersion
def QueryQMake(attrib): def QueryQMake(attrib):
return subprocess.check_output([qmake_path, '-query', attrib]).rstrip('\n') return subprocess.check_output([qmake_path, '-query', attrib]).rstrip('\n')
@@ -92,6 +93,8 @@ commands.append(['mkdir', '-p', resources_dir])
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns') plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
binaries = [i for i in glob(os.path.join(bundle_dir, 'Contents', 'MacOS', "*")) if is_exe(i)]; binaries = [i for i in glob(os.path.join(bundle_dir, 'Contents', 'MacOS', "*")) if is_exe(i)];
qt_version = QueryQMake('QT_VERSION')
print "Using Qt", qt_version
fixed_libraries = [] fixed_libraries = []
fixed_frameworks = [] fixed_frameworks = []
@@ -334,9 +337,19 @@ def FindQtPlugin(name):
for binary in binaries: for binary in binaries:
FixBinary(binary) FixBinary(binary)
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
QT_PLUGINS.append('styles/libqmacstyle.dylib')
for plugin in QT_PLUGINS: for plugin in QT_PLUGINS:
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin)) FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.10.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
commands.append(args)
else:
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.7.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
commands.append(args)
if len(sys.argv) <= 2: if len(sys.argv) <= 2:
print 'Will run %d commands:' % len(commands) print 'Will run %d commands:' % len(commands)
for command in commands: for command in commands:

View File

@@ -27,11 +27,9 @@
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>@MIRALL_VERSION_STRING@</string> <string>@MIRALL_VERSION_STRING@</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>(C) 2014-2016 @APPLICATION_VENDOR@</string> <string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
<key>SUShowReleaseNotes</key> <key>SUShowReleaseNotes</key>
<false/> <false/>
<key>LSMinimumBundleVersion</key>
<string>10.7.0</string>
<key>SUPublicDSAKeyFile</key> <key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string> <string>dsa_pub.pem</string>
</dict> </dict>

View File

@@ -278,6 +278,90 @@ X-GNOME-Autostart-Delay=3
# Translations # Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations # Translations
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
GenericName[oc]=Dorsièr de Sincronizacion GenericName[oc]=Dorsièr de Sincronizacion
@@ -362,6 +446,10 @@ Comment[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
GenericName[ko]=폴더 동기화 GenericName[ko]=폴더 동기화
Name[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트 Name[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
Icon[ko]=@APPLICATION_EXECUTABLE@ Icon[ko]=@APPLICATION_EXECUTABLE@
Comment[lo]=@APPLICATION_NAME@ ການປະສານຂໍ້ມູນຄອມພິວເຕີລູກຂ່າຍ
GenericName[lo]=ໂຟນເດີຊິງ
Name[lo]=@APPLICATION_NAME@ ຊິງຄອມພິວເຕີລູກຂ່າຍ
Icon[lo]=@APPLICATION_EXECUTABLE@
Comment[hu_HU]=@APPLICATION_NAME@ asztali szinkronizációs kliens Comment[hu_HU]=@APPLICATION_NAME@ asztali szinkronizációs kliens
GenericName[hu_HU]=Könyvtár szinkronizálás GenericName[hu_HU]=Könyvtár szinkronizálás
Name[hu_HU]=@APPLICATION_NAME@ asztali szinkr. kliens Name[hu_HU]=@APPLICATION_NAME@ asztali szinkr. kliens

View File

@@ -34,12 +34,15 @@ from gi.repository import GObject, Nautilus
appname = 'ownCloud' appname = 'ownCloud'
print("Initializing "+appname+"-client-nautilus extension") print("Initializing "+appname+"-client-nautilus extension")
print("Using python version {}".format(sys.version_info))
def get_local_path(url): def get_local_path(url):
if url[0:7] == 'file://': if url[0:7] == 'file://':
url = url[7:] url = url[7:]
unquote = urllib.parse.unquote if python3 else urllib.unquote if python3:
return unquote(url) return urllib.parse.unquote(url)
else:
return urllib.unquote(url).decode('utf-8')
def get_runtime_dir(): def get_runtime_dir():
"""Returns the value of $XDG_RUNTIME_DIR, a directory path. """Returns the value of $XDG_RUNTIME_DIR, a directory path.
@@ -61,7 +64,7 @@ class SocketConnect(GObject.GObject):
self._watch_id = 0 self._watch_id = 0
self._sock = None self._sock = None
self._listeners = [self._update_registered_paths] self._listeners = [self._update_registered_paths]
self._remainder = ''.encode() self._remainder = ''.encode('utf-8')
self.nautilusVFSFile_table = {} # not needed in this object actually but shared self.nautilusVFSFile_table = {} # not needed in this object actually but shared
# all over the other objects. # all over the other objects.
@@ -79,7 +82,7 @@ class SocketConnect(GObject.GObject):
# print("Server command: " + cmd) # print("Server command: " + cmd)
if self.connected: if self.connected:
try: try:
self._sock.send(cmd.encode()) self._sock.send(cmd.encode('utf-8'))
except: except:
print("Sending failed.") print("Sending failed.")
self.reconnect() self.reconnect()
@@ -94,18 +97,15 @@ class SocketConnect(GObject.GObject):
self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock_file = os.path.join(get_runtime_dir(), appname, "socket") sock_file = os.path.join(get_runtime_dir(), appname, "socket")
try: try:
print("Socket File: " + sock_file)
self._sock.connect(sock_file) # fails if sock_file doesn't exist self._sock.connect(sock_file) # fails if sock_file doesn't exist
self.connected = True self.connected = True
print("Setting connected to %r." % self.connected )
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify) self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
print("Socket watch id: " + str(self._watch_id))
self.sendCommand('GET_STRINGS:\n') self.sendCommand('GET_STRINGS:\n')
return False # Don't run again return False # Don't run again
except Exception as e: except Exception as e:
print("Could not connect to unix socket. " + str(e)) print("Could not connect to unix socket " + sock_file + ". " + str(e))
except Exception as e: # Bad habbit except Exception as e: # Bad habbit
print("Connect could not be established, try again later.") print("Connect could not be established, try again later.")
self._sock.close() self._sock.close()
@@ -118,24 +118,24 @@ class SocketConnect(GObject.GObject):
# Prepend the remaining data from last call # Prepend the remaining data from last call
if len(self._remainder) > 0: if len(self._remainder) > 0:
data = self._remainder + data data = self._remainder + data
self._remainder = ''.encode() self._remainder = ''.encode('utf-8')
if len(data) > 0: if len(data) > 0:
# Remember the remainder for next round # Remember the remainder for next round
lastNL = data.rfind('\n'.encode()); lastNL = data.rfind('\n'.encode('utf-8'));
if lastNL > -1 and lastNL < len(data): if lastNL > -1 and lastNL < len(data):
self._remainder = data[lastNL+1:] self._remainder = data[lastNL+1:]
data = data[:lastNL] data = data[:lastNL]
for l in data.split('\n'.encode()): for l in data.split('\n'.encode('utf-8')):
self._handle_server_response(l.decode()) self._handle_server_response(l.decode('utf-8'))
else: else:
return False return False
return True # Run again return True # Run again
def _handle_server_response(self, line): def _handle_server_response(self, line):
print("Server response: " + line) # print("Server response: " + line)
parts = line.split(':') parts = line.split(':')
action = parts[0] action = parts[0]
args = parts[1:] args = parts[1:]
@@ -262,11 +262,11 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
def context_menu_action(self, menu, action, file): def context_menu_action(self, menu, action, file):
filename = get_local_path(file.get_uri()) filename = get_local_path(file.get_uri())
print("Context menu: " + action + ' ' + filename) # print("Context menu: " + action + ' ' + filename)
socketConnect.sendCommand(action + ":" + filename + "\n") socketConnect.sendCommand(action + ":" + filename + "\n")
class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider): class SyncStateExtension(GObject.GObject, Nautilus.InfoProvider):
def __init__(self): def __init__(self):
GObject.GObject.__init__(self) GObject.GObject.__init__(self)

View File

@@ -65,7 +65,7 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que
static QString defaultJournalMode(const QString &dbPath) static QString defaultJournalMode(const QString &dbPath)
{ {
#ifdef Q_OS_WIN #if defined(Q_OS_WIN)
// See #2693: Some exFAT file systems seem unable to cope with the // See #2693: Some exFAT file systems seem unable to cope with the
// WAL journaling mode. They work fine with DELETE. // WAL journaling mode. They work fine with DELETE.
QString fileSystem = FileSystem::fileSystemForPath(dbPath); QString fileSystem = FileSystem::fileSystemForPath(dbPath);
@@ -74,6 +74,11 @@ static QString defaultJournalMode(const QString &dbPath)
qCInfo(lcDb) << "Filesystem contains FAT - using DELETE journal mode"; qCInfo(lcDb) << "Filesystem contains FAT - using DELETE journal mode";
return "DELETE"; return "DELETE";
} }
#elif defined(Q_OS_MAC)
if (dbPath.startsWith("/Volumes/")) {
qCInfo(lcDb) << "Mounted sync dir, do not use WAL for" << dbPath;
return "DELETE";
}
#else #else
Q_UNUSED(dbPath) Q_UNUSED(dbPath)
#endif #endif
@@ -271,6 +276,11 @@ bool SyncJournalDb::sqlFail(const QString &log, const SqlQuery &query)
bool SyncJournalDb::checkConnect() bool SyncJournalDb::checkConnect()
{ {
if (_db.isOpen()) { if (_db.isOpen()) {
if (!QFile::exists(_dbFile)) {
qCWarning(lcDb) << "Database open, but file file" + _dbFile + " does not exist";
close();
return false;
}
return true; return true;
} }

View File

@@ -1,13 +1,6 @@
PROJECT( CrashReporter ) PROJECT( CrashReporter )
cmake_policy(SET CMP0017 NEW) cmake_policy(SET CMP0017 NEW)
list(APPEND crashreporter_SOURCES main.cpp)
list(APPEND crashreporter_RC resources.qrc)
qt_wrap_ui( crashreporter_UI_HEADERS ${crashreporter_UI} )
qt_add_resources( crashreporter_RC_RCC ${crashreporter_RC} )
# TODO: differentiate release channel # TODO: differentiate release channel
# if(BUILD_RELEASE) # if(BUILD_RELEASE)
# set(CRASHREPORTER_RELEASE_CHANNEL "release") # set(CRASHREPORTER_RELEASE_CHANNEL "release")
@@ -15,9 +8,30 @@ qt_add_resources( crashreporter_RC_RCC ${crashreporter_RC} )
set(CRASHREPORTER_RELEASE_CHANNEL "nightly") set(CRASHREPORTER_RELEASE_CHANNEL "nightly")
# endif() # endif()
# Theme
if(DEFINED OEM_THEME_DIR AND EXISTS "${OEM_THEME_DIR}/theme/colored")
set(CRASHREPORTER_ICON_DIR "${OEM_THEME_DIR}/theme/colored")
else()
set(CRASHREPORTER_ICON_DIR "${CMAKE_SOURCE_DIR}/theme/colored")
endif()
set(CRASHREPORTER_ICON_FILENAME "${APPLICATION_ICON_NAME}-icon.png")
set(CRASHREPORTER_ICON ":/${CRASHREPORTER_ICON_FILENAME}")
set(CRASHREPORTER_ICON_SIZE "128")
set(CRASHREPORTER_ICON_PATH "${CRASHREPORTER_ICON_DIR}/${APPLICATION_ICON_NAME}-icon-${CRASHREPORTER_ICON_SIZE}.png")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources.qrc.in
${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CrashReporterConfig.h.in configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CrashReporterConfig.h.in
${CMAKE_CURRENT_BINARY_DIR}/CrashReporterConfig.h) ${CMAKE_CURRENT_BINARY_DIR}/CrashReporterConfig.h)
# Sources
list(APPEND crashreporter_SOURCES main.cpp)
list(APPEND crashreporter_RC "${CMAKE_CURRENT_BINARY_DIR}/resources.qrc")
qt_wrap_ui( crashreporter_UI_HEADERS ${crashreporter_UI} )
qt_add_resources( crashreporter_RC_RCC ${crashreporter_RC} )
include_directories(${CMAKE_CURRENT_BINARY_DIR} include_directories(${CMAKE_CURRENT_BINARY_DIR}
"../3rdparty/libcrashreporter-qt/src/" "../3rdparty/libcrashreporter-qt/src/"

View File

@@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/">
<file alias="owncloud-icon.png">../../theme/colored/owncloud-icon-128.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file alias="@CRASHREPORTER_ICON_FILENAME@">@CRASHREPORTER_ICON_PATH@</file>
</qresource>
</RCC>

View File

@@ -156,7 +156,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
/* First, check that the file is NOT in our tree (another file with the same name was added) */ /* First, check that the file is NOT in our tree (another file with the same name was added) */
if (our_tree->findFile(basePath)) { if (our_tree->findFile(basePath)) {
other = nullptr; other = nullptr;
qCDebug(lcReconcile, "Origin found in our tree : %s", basePath.constData()); qCInfo(lcReconcile, "Origin found in our tree : %s", basePath.constData());
} else { } else {
/* Find the potential rename source file in the other tree. /* Find the potential rename source file in the other tree.
* If the renamed file could not be found in the opposite tree, that is because it * If the renamed file could not be found in the opposite tree, that is because it
@@ -164,7 +164,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
* The journal is cleaned up later after propagation. * The journal is cleaned up later after propagation.
*/ */
other = other_tree->findFile(basePath); other = other_tree->findFile(basePath);
qCDebug(lcReconcile, "Rename origin in other tree (%s) %s", qCInfo(lcReconcile, "Rename origin in other tree (%s) %s",
basePath.constData(), other ? "found" : "not found"); basePath.constData(), other ? "found" : "not found");
} }
@@ -175,7 +175,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// Some other EVAL_RENAME already claimed other. // Some other EVAL_RENAME already claimed other.
// We do nothing: maybe a different candidate for // We do nothing: maybe a different candidate for
// other is found as well? // other is found as well?
qCDebug(lcReconcile, "Other has already been renamed to %s", qCInfo(lcReconcile, "Other has already been renamed to %s",
other->rename_path.constData()); other->rename_path.constData());
} else if (cur->type == CSYNC_FTW_TYPE_DIR } else if (cur->type == CSYNC_FTW_TYPE_DIR
// The local replica is reconciled first, so the remote tree would // The local replica is reconciled first, so the remote tree would
@@ -187,13 +187,17 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
|| other->instruction == CSYNC_INSTRUCTION_NONE || other->instruction == CSYNC_INSTRUCTION_NONE
|| other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
|| other->instruction == CSYNC_INSTRUCTION_REMOVE) { || other->instruction == CSYNC_INSTRUCTION_REMOVE) {
qCDebug(lcReconcile, "Switching %s to RENAME to %s", qCInfo(lcReconcile, "Switching %s to RENAME to %s",
other->path.constData(), cur->path.constData()); other->path.constData(), cur->path.constData());
other->instruction = CSYNC_INSTRUCTION_RENAME; other->instruction = CSYNC_INSTRUCTION_RENAME;
other->rename_path = cur->path; other->rename_path = cur->path;
if( !cur->file_id.isEmpty() ) { if( !cur->file_id.isEmpty() ) {
other->file_id = cur->file_id; other->file_id = cur->file_id;
} }
if (ctx->current == LOCAL_REPLICA) {
// Keep the local mtime.
other->modtime = cur->modtime;
}
other->inode = cur->inode; other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE; cur->instruction = CSYNC_INSTRUCTION_NONE;
// We have consumed 'other': exit this loop to not consume another one. // We have consumed 'other': exit this loop to not consume another one.
@@ -207,7 +211,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// Local: The remote reconcile will be able to deal with this. // Local: The remote reconcile will be able to deal with this.
// Remote: The local replica has already dealt with this. // Remote: The local replica has already dealt with this.
// See the EVAL_RENAME case when other was found directly. // See the EVAL_RENAME case when other was found directly.
qCDebug(lcReconcile, "File in a renamed directory, other side's instruction: %d", qCInfo(lcReconcile, "File in a renamed directory, other side's instruction: %d",
other->instruction); other->instruction);
cur->instruction = CSYNC_INSTRUCTION_NONE; cur->instruction = CSYNC_INSTRUCTION_NONE;
} else { } else {
@@ -215,7 +219,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// and the instruction in the local tree is NEW while cur has EVAL_RENAME // and the instruction in the local tree is NEW while cur has EVAL_RENAME
// due to a remote move of the same file. In these scenarios we just // due to a remote move of the same file. In these scenarios we just
// want the instruction to stay NEW. // want the instruction to stay NEW.
qCDebug(lcReconcile, "Other already has instruction %d", qCInfo(lcReconcile, "Other already has instruction %d",
other->instruction); other->instruction);
} }
}; };
@@ -223,7 +227,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
if (ctx->current == LOCAL_REPLICA) { if (ctx->current == LOCAL_REPLICA) {
/* use the old name to find the "other" node */ /* use the old name to find the "other" node */
OCC::SyncJournalFileRecord base; OCC::SyncJournalFileRecord base;
qCDebug(lcReconcile, "Finding rename origin through inode %" PRIu64 "", qCInfo(lcReconcile, "Finding rename origin through inode %" PRIu64 "",
cur->inode); cur->inode);
ctx->statedb->getFileRecordByInode(cur->inode, &base); ctx->statedb->getFileRecordByInode(cur->inode, &base);
renameCandidateProcessing(base._path); renameCandidateProcessing(base._path);
@@ -236,7 +240,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// line. // line.
auto basePath = csync_rename_adjust_full_path_source(ctx, cur->path); auto basePath = csync_rename_adjust_full_path_source(ctx, cur->path);
if (basePath != cur->path) { if (basePath != cur->path) {
qCDebug(lcReconcile, "Trying rename origin by csync_rename mapping %s", qCInfo(lcReconcile, "Trying rename origin by csync_rename mapping %s",
basePath.constData()); basePath.constData());
// We go through getFileRecordsByFileId to ensure the basePath // We go through getFileRecordsByFileId to ensure the basePath
// computed in this way also has the expected fileid. // computed in this way also has the expected fileid.
@@ -249,7 +253,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// Also feed all the other files with the same fileid if necessary // Also feed all the other files with the same fileid if necessary
if (!processedRename) { if (!processedRename) {
qCDebug(lcReconcile, "Finding rename origin through file ID %s", qCInfo(lcReconcile, "Finding rename origin through file ID %s",
cur->file_id.constData()); cur->file_id.constData());
ctx->statedb->getFileRecordsByFileId(cur->file_id, ctx->statedb->getFileRecordsByFileId(cur->file_id,
[&](const OCC::SyncJournalFileRecord &base) { renameCandidateProcessing(base._path); }); [&](const OCC::SyncJournalFileRecord &base) { renameCandidateProcessing(base._path); });

View File

@@ -130,12 +130,12 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
* This code should probably be in csync_exclude, but it does not have the fs parameter. * This code should probably be in csync_exclude, but it does not have the fs parameter.
* Keep it here for now */ * Keep it here for now */
if (ctx->ignore_hidden_files && (fs->is_hidden)) { if (ctx->ignore_hidden_files && (fs->is_hidden)) {
qCDebug(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData()); qCInfo(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData());
excluded = CSYNC_FILE_EXCLUDE_HIDDEN; excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
} }
} else { } else {
/* File is ignored because it's matched by a user- or system exclude pattern. */ /* File is ignored because it's matched by a user- or system exclude pattern. */
qCDebug(lcUpdate, "%s excluded (%d)", fs->path.constData(), excluded); qCInfo(lcUpdate, "%s excluded (%d)", fs->path.constData(), excluded);
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) { if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
return 1; return 1;
} }
@@ -160,7 +160,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
*/ */
QTextEncoder encoder(localCodec, QTextCodec::ConvertInvalidToNull); QTextEncoder encoder(localCodec, QTextCodec::ConvertInvalidToNull);
if (encoder.fromUnicode(QString::fromUtf8(fs->path)).contains('\0')) { if (encoder.fromUnicode(QString::fromUtf8(fs->path)).contains('\0')) {
qCDebug(lcUpdate, "cannot encode %s to local encoding %d", qCInfo(lcUpdate, "cannot encode %s to local encoding %d",
fs->path.constData(), localCodec->mibEnum()); fs->path.constData(), localCodec->mibEnum());
excluded = CSYNC_FILE_EXCLUDE_CANNOT_ENCODE; excluded = CSYNC_FILE_EXCLUDE_CANNOT_ENCODE;
} }
@@ -168,7 +168,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
if (fs->type == CSYNC_FTW_TYPE_FILE ) { if (fs->type == CSYNC_FTW_TYPE_FILE ) {
if (fs->modtime == 0) { if (fs->modtime == 0) {
qCDebug(lcUpdate, "file: %s - mtime is zero!", fs->path.constData()); qCInfo(lcUpdate, "file: %s - mtime is zero!", fs->path.constData());
} }
} }
@@ -195,10 +195,12 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
/* we have an update! */ /* we have an update! */
qCInfo(lcUpdate, "Database entry found, compare: %" PRId64 " <-> %" PRId64 qCInfo(lcUpdate, "Database entry found, compare: %" PRId64 " <-> %" PRId64
", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64 ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
", size: %" PRId64 " <-> %" PRId64 ", perms: %x <-> %x, ignore: %d", ", size: %" PRId64 " <-> %" PRId64 ", perms: %x <-> %x"
", checksum: %s <-> %s , ignore: %d",
((int64_t) fs->modtime), ((int64_t) base._modtime), ((int64_t) fs->modtime), ((int64_t) base._modtime),
fs->etag.constData(), base._etag.constData(), (uint64_t) fs->inode, (uint64_t) base._inode, fs->etag.constData(), base._etag.constData(), (uint64_t) fs->inode, (uint64_t) base._inode,
(uint64_t) fs->size, (uint64_t) base._fileSize, *reinterpret_cast<short*>(&fs->remotePerm), *reinterpret_cast<short*>(&base._remotePerm), base._serverHasIgnoredFiles ); (uint64_t) fs->size, (uint64_t) base._fileSize, *reinterpret_cast<short*>(&fs->remotePerm), *reinterpret_cast<short*>(&base._remotePerm), fs->checksumHeader.constData(),
base._checksumHeader.constData(), base._serverHasIgnoredFiles);
if (ctx->current == REMOTE_REPLICA && fs->etag != base._etag) { if (ctx->current == REMOTE_REPLICA && fs->etag != base._etag) {
fs->instruction = CSYNC_INSTRUCTION_EVAL; fs->instruction = CSYNC_INSTRUCTION_EVAL;
@@ -228,7 +230,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
checksumIdentical = fs->checksumHeader == base._checksumHeader; checksumIdentical = fs->checksumHeader == base._checksumHeader;
} }
if (checksumIdentical) { if (checksumIdentical) {
qCDebug(lcUpdate, "NOTE: Checksums are identical, file did not actually change: %s", fs->path.constData()); qCInfo(lcUpdate, "NOTE: Checksums are identical, file did not actually change: %s", fs->path.constData());
fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
goto out; goto out;
} }
@@ -252,7 +254,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
* The metadata comparison ensure that we fetch all the file id or permission when * The metadata comparison ensure that we fetch all the file id or permission when
* upgrading owncloud * upgrading owncloud
*/ */
qCDebug(lcUpdate, "Reading from database: %s", fs->path.constData()); qCInfo(lcUpdate, "Reading from database: %s", fs->path.constData());
ctx->remote.read_from_db = true; ctx->remote.read_from_db = true;
} }
/* If it was remembered in the db that the remote dir has ignored files, store /* If it was remembered in the db that the remote dir has ignored files, store
@@ -263,7 +265,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
} }
if (metadata_differ) { if (metadata_differ) {
/* file id or permissions has changed. Which means we need to update them in the DB. */ /* file id or permissions has changed. Which means we need to update them in the DB. */
qCDebug(lcUpdate, "Need to update metadata for: %s", fs->path.constData()); qCInfo(lcUpdate, "Need to update metadata for: %s", fs->path.constData());
fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
} else { } else {
fs->instruction = CSYNC_INSTRUCTION_NONE; fs->instruction = CSYNC_INSTRUCTION_NONE;
@@ -271,7 +273,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
} else { } else {
/* check if it's a file and has been renamed */ /* check if it's a file and has been renamed */
if (ctx->current == LOCAL_REPLICA) { if (ctx->current == LOCAL_REPLICA) {
qCDebug(lcUpdate, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode); qCInfo(lcUpdate, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
OCC::SyncJournalFileRecord base; OCC::SyncJournalFileRecord base;
if(!ctx->statedb->getFileRecordByInode(fs->inode, &base)) { if(!ctx->statedb->getFileRecordByInode(fs->inode, &base)) {
@@ -298,13 +300,13 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
_rel_to_abs(ctx, fs->path), base._checksumHeader, _rel_to_abs(ctx, fs->path), base._checksumHeader,
ctx->callbacks.checksum_userdata); ctx->callbacks.checksum_userdata);
if (!fs->checksumHeader.isEmpty()) { if (!fs->checksumHeader.isEmpty()) {
qCDebug(lcUpdate, "checking checksum of potential rename %s %s <-> %s", fs->path.constData(), fs->checksumHeader.constData(), base._checksumHeader.constData()); qCInfo(lcUpdate, "checking checksum of potential rename %s %s <-> %s", fs->path.constData(), fs->checksumHeader.constData(), base._checksumHeader.constData());
isRename = fs->checksumHeader == base._checksumHeader; isRename = fs->checksumHeader == base._checksumHeader;
} }
} }
if (isRename) { if (isRename) {
qCDebug(lcUpdate, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode); qCInfo(lcUpdate, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
/* inode found so the file has been renamed */ /* inode found so the file has been renamed */
fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
if (fs->type == CSYNC_FTW_TYPE_DIR) { if (fs->type == CSYNC_FTW_TYPE_DIR) {
@@ -314,6 +316,8 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
goto out; goto out;
} else { } else {
qCInfo(lcUpdate, "Checking for rename based on fileid %s", fs->file_id.constData());
/* Remote Replica Rename check */ /* Remote Replica Rename check */
fs->instruction = CSYNC_INSTRUCTION_NEW; fs->instruction = CSYNC_INSTRUCTION_NEW;
@@ -350,7 +354,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
csync_rename_record(ctx, base._path, fs->path); csync_rename_record(ctx, base._path, fs->path);
} }
qCDebug(lcUpdate, "remote rename detected based on fileid %s --> %s", base._path.constData(), fs->path.constData()); qCInfo(lcUpdate, "remote rename detected based on fileid %s --> %s", base._path.constData(), fs->path.constData());
fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
done = true; done = true;
}; };
@@ -458,11 +462,11 @@ int csync_walker(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
} }
break; break;
case CSYNC_FTW_TYPE_SLINK: case CSYNC_FTW_TYPE_SLINK:
qCDebug(lcUpdate, "symlink: %s - not supported", fs->path.constData()); qCInfo(lcUpdate, "symlink: %s - not supported", fs->path.constData());
break; break;
default: default:
qCInfo(lcUpdate, "item: %s - item type %d not iterated", fs->path.constData(), fs->type);
return 0; return 0;
break;
} }
rc = _csync_detect_update(ctx, std::move(fs)); rc = _csync_detect_update(ctx, std::move(fs));
@@ -483,7 +487,7 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
* their correct etags again and we don't run into this case. * their correct etags again and we don't run into this case.
*/ */
if( rec._etag == "_invalid_") { if( rec._etag == "_invalid_") {
qCDebug(lcUpdate, "%s selective sync excluded", rec._path.constData()); qCInfo(lcUpdate, "%s selective sync excluded", rec._path.constData());
skipbase = rec._path; skipbase = rec._path;
skipbase += '/'; skipbase += '/';
return; return;
@@ -720,7 +724,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
} }
csync_vio_closedir(ctx, dh); csync_vio_closedir(ctx, dh);
qCDebug(lcUpdate, " <= Closing walk for %s with read_from_db %d", uri, read_from_db); qCInfo(lcUpdate, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);
return rc; return rc;

View File

@@ -136,7 +136,7 @@ IF( APPLE )
if(SPARKLE_FOUND) if(SPARKLE_FOUND)
# Define this, we need to check in updater.cpp # Define this, we need to check in updater.cpp
add_definitions( -DHAVE_SPARKLE ) add_definitions( -DHAVE_SPARKLE )
list(APPEND updater_SRCS updater/sparkleupdater_mac.mm) list(APPEND updater_SRCS updater/sparkleupdater_mac.mm updater/sparkleupdater.h)
endif() endif()
ENDIF() ENDIF()

View File

@@ -312,10 +312,10 @@ void AccountState::slotInvalidCredentials()
if (account()->credentials()->ready()) { if (account()->credentials()->ready()) {
account()->credentials()->invalidateToken(); account()->credentials()->invalidateToken();
if (auto creds = qobject_cast<HttpCredentials *>(account()->credentials())) { }
if (creds->refreshAccessToken()) if (auto creds = qobject_cast<HttpCredentials *>(account()->credentials())) {
return; if (creds->refreshAccessToken())
} return;
} }
account()->credentials()->askFromUser(); account()->credentials()->askFromUser();
} }

View File

@@ -121,6 +121,10 @@ void Folder::checkLocalPath()
{ {
const QFileInfo fi(_definition.localPath); const QFileInfo fi(_definition.localPath);
_canonicalLocalPath = fi.canonicalFilePath(); _canonicalLocalPath = fi.canonicalFilePath();
#ifdef Q_OS_MAC
// Workaround QTBUG-55896 (Should be fixed in Qt 5.8)
_canonicalLocalPath = _canonicalLocalPath.normalized(QString::NormalizationForm_C);
#endif
if (_canonicalLocalPath.isEmpty()) { if (_canonicalLocalPath.isEmpty()) {
qCWarning(lcFolder) << "Broken symlink:" << _definition.localPath; qCWarning(lcFolder) << "Broken symlink:" << _definition.localPath;
_canonicalLocalPath = _definition.localPath; _canonicalLocalPath = _definition.localPath;

View File

@@ -25,6 +25,10 @@
#include "updater/updater.h" #include "updater/updater.h"
#include "updater/ocupdater.h" #include "updater/ocupdater.h"
#ifdef Q_OS_MAC
// FIXME We should unify those, but Sparkle does everything behind the scene transparently
#include "updater/sparkleupdater.h"
#endif
#include "ignorelisteditor.h" #include "ignorelisteditor.h"
#include "config.h" #include "config.h"
@@ -32,6 +36,7 @@
#include <QNetworkProxy> #include <QNetworkProxy>
#include <QDir> #include <QDir>
#include <QScopedValueRollback> #include <QScopedValueRollback>
#include <QMessageBox>
namespace OCC { namespace OCC {
@@ -88,6 +93,18 @@ GeneralSettings::GeneralSettings(QWidget *parent)
// accountAdded means the wizard was finished and the wizard might change some options. // accountAdded means the wizard was finished and the wizard might change some options.
connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings); connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings);
// Only our standard brandings currently support beta channel
Theme *theme = Theme::instance();
if (theme->appName() != QLatin1String("ownCloud") && theme->appName() != QLatin1String("testpilotcloud") ) {
#ifdef Q_OS_MAC
// Because we don't have any statusString from the SparkleUpdater anyway we can hide the whole thing
_ui->updatesGroupBox->hide();
#else
_ui->updateChannelLabel->hide();
_ui->updateChannel->hide();
#endif
}
} }
GeneralSettings::~GeneralSettings() GeneralSettings::~GeneralSettings()
@@ -117,22 +134,79 @@ void GeneralSettings::loadMiscSettings()
void GeneralSettings::slotUpdateInfo() void GeneralSettings::slotUpdateInfo()
{ {
// Note: the sparkle-updater is not an OCUpdater if (ConfigFile().skipUpdateCheck() || !Updater::instance()) {
OCUpdater *updater = qobject_cast<OCUpdater *>(Updater::instance()); // updater disabled on compile
if (ConfigFile().skipUpdateCheck()) { _ui->updatesGroupBox->setVisible(false);
updater = 0; // don't show update info if updates are disabled return;
} }
if (updater) { // Note: the sparkle-updater is not an OCUpdater
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection); OCUpdater *ocupdater = qobject_cast<OCUpdater *>(Updater::instance());
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection); if (ocupdater) {
connect(ocupdater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
connect(_ui->restartButton, &QAbstractButton::clicked, ocupdater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection); connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection);
_ui->updateStateLabel->setText(updater->statusString());
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete); _ui->updateStateLabel->setText(ocupdater->statusString());
} else { _ui->restartButton->setVisible(ocupdater->downloadState() == OCUpdater::DownloadComplete);
// can't have those infos from sparkle currently
_ui->updatesGroupBox->setVisible(false);
} }
#ifdef Q_OS_MAC
else if (SparkleUpdater *sparkleUpdater = qobject_cast<SparkleUpdater *>(Updater::instance())) {
_ui->updateStateLabel->setText(sparkleUpdater->statusString());
_ui->restartButton->setVisible(false);
}
#endif
// Channel selection
_ui->updateChannel->setCurrentIndex(ConfigFile().updateChannel() == "beta" ? 1 : 0);
connect(_ui->updateChannel, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &GeneralSettings::slotUpdateChannelChanged, Qt::UniqueConnection);
}
void GeneralSettings::slotUpdateChannelChanged(int index)
{
QString channel = index == 0 ? QStringLiteral("stable") : QStringLiteral("beta");
if (channel == ConfigFile().updateChannel())
return;
auto msgBox = new QMessageBox(
QMessageBox::Warning,
tr("Change update channel?"),
tr("The update channel determines which client updates will be offered "
"for installation. The \"stable\" channel contains only upgrades that "
"are considered reliable, while the versions in the \"beta\" channel "
"may contain newer features and bugfixes, but have not yet been tested "
"thoroughly."
"\n\n"
"Note that this selects only what pool upgrades are taken from, and that "
"there are no downgrades: So going back from the beta channel to "
"the stable channel usually cannot be done immediately and means waiting "
"for a stable version that is newer than the currently installed beta "
"version."),
QMessageBox::NoButton,
this);
msgBox->addButton(tr("Change update channel"), QMessageBox::AcceptRole);
msgBox->addButton(tr("Cancel"), QMessageBox::RejectRole);
connect(msgBox, &QMessageBox::finished, msgBox, [this, channel, msgBox](int result) {
msgBox->deleteLater();
if (result == QMessageBox::AcceptRole) {
ConfigFile().setUpdateChannel(channel);
if (OCUpdater *updater = qobject_cast<OCUpdater *>(Updater::instance())) {
updater->setUpdateUrl(Updater::updateUrl());
updater->checkForUpdate();
}
#ifdef Q_OS_MAC
else if (SparkleUpdater *updater = qobject_cast<SparkleUpdater *>(Updater::instance())) {
updater->setUpdateUrl(Updater::updateUrl());
updater->checkForUpdate();
}
#endif
} else {
_ui->updateChannel->setCurrentText(ConfigFile().updateChannel());
}
});
msgBox->open();
} }
void GeneralSettings::saveMiscSettings() void GeneralSettings::saveMiscSettings()

View File

@@ -44,6 +44,7 @@ private slots:
void slotToggleLaunchOnStartup(bool); void slotToggleLaunchOnStartup(bool);
void slotToggleOptionalDesktopNotifications(bool); void slotToggleOptionalDesktopNotifications(bool);
void slotUpdateInfo(); void slotUpdateInfo();
void slotUpdateChannelChanged(int index);
void slotIgnoreFilesEditor(); void slotIgnoreFilesEditor();
void loadMiscSettings(); void loadMiscSettings();

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>785</width> <width>785</width>
<height>523</height> <height>533</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -74,48 +74,88 @@
<property name="title"> <property name="title">
<string>Updates</string> <string>Updates</string>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QLabel" name="updateStateLabel"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="text"> <item>
<string/> <widget class="QLabel" name="updateChannelLabel">
</property> <property name="sizePolicy">
<property name="wordWrap"> <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<bool>true</bool> <horstretch>0</horstretch>
</property> <verstretch>0</verstretch>
<property name="openExternalLinks"> </sizepolicy>
<bool>true</bool> </property>
</property> <property name="text">
</widget> <string>&amp;Channel</string>
</item> </property>
<item> <property name="buddy">
<widget class="QPushButton" name="restartButton"> <cstring>updateChannel</cstring>
<property name="sizePolicy"> </property>
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> </widget>
<horstretch>0</horstretch> </item>
<verstretch>0</verstretch> <item>
</sizepolicy> <widget class="QComboBox" name="updateChannel">
</property> <property name="sizePolicy">
<property name="text"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<string>&amp;Restart &amp;&amp; Update</string> <horstretch>0</horstretch>
</property> <verstretch>0</verstretch>
</widget> </sizepolicy>
</item> </property>
<item> <item>
<spacer name="horizontalSpacer"> <property name="text">
<property name="orientation"> <string>stable</string>
<enum>Qt::Horizontal</enum> </property>
</property> </item>
<property name="sizeType"> <item>
<enum>QSizePolicy::Preferred</enum> <property name="text">
</property> <string>beta</string>
<property name="sizeHint" stdset="0"> </property>
<size> </item>
<width>40</width> </widget>
<height>20</height> </item>
</size> <item>
</property> <widget class="QLabel" name="updateStateLabel">
</spacer> <property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="restartButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Restart &amp;&amp; Update</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
@@ -247,7 +287,10 @@
<tabstop>ignoredFilesButton</tabstop> <tabstop>ignoredFilesButton</tabstop>
<tabstop>newFolderLimitCheckBox</tabstop> <tabstop>newFolderLimitCheckBox</tabstop>
<tabstop>newFolderLimitSpinBox</tabstop> <tabstop>newFolderLimitSpinBox</tabstop>
<tabstop>newExternalStorage</tabstop>
<tabstop>showInExplorerNavigationPaneCheckBox</tabstop>
<tabstop>crashreporterCheckBox</tabstop> <tabstop>crashreporterCheckBox</tabstop>
<tabstop>updateChannel</tabstop>
<tabstop>restartButton</tabstop> <tabstop>restartButton</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>

View File

@@ -50,18 +50,13 @@ const char propertyAccountC[] = "oc_account";
ownCloudGui::ownCloudGui(Application *parent) ownCloudGui::ownCloudGui(Application *parent)
: QObject(parent) : QObject(parent)
, _tray(0) , _tray(0)
,
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
_settingsDialog(new SettingsDialogMac(this)) , _settingsDialog(new SettingsDialogMac(this))
,
#else #else
_settingsDialog(new SettingsDialog(this)) , _settingsDialog(new SettingsDialog(this))
,
#endif #endif
_logBrowser(0) , _logBrowser(0)
, _contextMenuVisibleOsx(false)
, _recentActionsMenu(0) , _recentActionsMenu(0)
, _qdbusmenuWorkaround(false)
, _app(parent) , _app(parent)
{ {
_tray = new Systray(); _tray = new Systray();
@@ -117,7 +112,7 @@ void ownCloudGui::slotOpenSettingsDialog()
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason) void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
{ {
if (_qdbusmenuWorkaround) { if (_workaroundFakeDoubleClick) {
static QElapsedTimer last_click; static QElapsedTimer last_click;
if (last_click.isValid() && last_click.elapsed() < 200) { if (last_click.isValid() && last_click.elapsed() < 200) {
return; return;
@@ -381,17 +376,19 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
void ownCloudGui::slotContextMenuAboutToShow() void ownCloudGui::slotContextMenuAboutToShow()
{ {
// For some reason on OS X _contextMenu->isVisible returns always false _contextMenuVisibleManual = true;
_contextMenuVisibleOsx = true;
// Update icon in sys tray, as it might change depending on the context menu state // Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus(); slotComputeOverallSyncStatus();
if (!_workaroundNoAboutToShowUpdate) {
updateContextMenu();
}
} }
void ownCloudGui::slotContextMenuAboutToHide() void ownCloudGui::slotContextMenuAboutToHide()
{ {
// For some reason on OS X _contextMenu->isVisible returns always false _contextMenuVisibleManual = false;
_contextMenuVisibleOsx = false;
// Update icon in sys tray, as it might change depending on the context menu state // Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus(); slotComputeOverallSyncStatus();
@@ -399,11 +396,11 @@ void ownCloudGui::slotContextMenuAboutToHide()
bool ownCloudGui::contextMenuVisible() const bool ownCloudGui::contextMenuVisible() const
{ {
#ifdef Q_OS_MAC // On some platforms isVisible doesn't work and always returns false,
return _contextMenuVisibleOsx; // elsewhere aboutToHide is unreliable.
#else if (_workaroundManualVisibility)
return _contextMenuVisibleManual;
return _contextMenu->isVisible(); return _contextMenu->isVisible();
#endif
} }
static bool minimalTrayMenu() static bool minimalTrayMenu()
@@ -426,12 +423,36 @@ static bool updateWhileVisible()
} }
} }
static QByteArray forceQDBusTrayWorkaround() static QByteArray envForceQDBusTrayWorkaround()
{ {
static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND"); static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND");
return var; return var;
} }
static QByteArray envForceWorkaroundShowAndHideTray()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_SHOW_HIDE");
return var;
}
static QByteArray envForceWorkaroundNoAboutToShowUpdate()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_NO_ABOUT_TO_SHOW");
return var;
}
static QByteArray envForceWorkaroundFakeDoubleClick()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_FAKE_DOUBLE_CLICK");
return var;
}
static QByteArray envForceWorkaroundManualVisibility()
{
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_MANUAL_VISIBILITY");
return var;
}
void ownCloudGui::setupContextMenu() void ownCloudGui::setupContextMenu()
{ {
if (_contextMenu) { if (_contextMenu) {
@@ -454,51 +475,65 @@ void ownCloudGui::setupContextMenu()
return; return;
} }
// Enables workarounds for bugs introduced in Qt 5.5.0 auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
// In particular QTBUG-47863 #3672 (tray menu fails to update and if (value == "1")
// becomes unresponsive) and QTBUG-48068 #3722 (click signal is *sw = true;
// emitted several times) if (value == "0")
// The Qt version check intentionally uses 5.0.0 (where platformMenu() *sw = false;
// was introduced) instead of 5.5.0 to avoid issues where the Qt };
// version used to build is different from the one used at runtime.
// If we build with 5.6.1 or newer, we can skip this because the
// bugs should be fixed there.
#ifdef Q_OS_LINUX
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
if (qVersion() == QByteArray("5.5.0")) {
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
if (platformMenu
&& platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
_qdbusmenuWorkaround = true;
qCWarning(lcApplication) << "Enabled QDBusPlatformMenu workaround";
}
}
#endif
#endif
if (forceQDBusTrayWorkaround() == "1") { // This is an old compound flag that people might still depend on
_qdbusmenuWorkaround = true; bool qdbusmenuWorkarounds = false;
} else if (forceQDBusTrayWorkaround() == "0") { applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
_qdbusmenuWorkaround = false; if (qdbusmenuWorkarounds) {
_workaroundFakeDoubleClick = true;
_workaroundNoAboutToShowUpdate = true;
_workaroundShowAndHideTray = true;
} }
// When the qdbusmenuWorkaround is necessary, we can't do on-demand updates
// because the workaround is to hide and show the tray icon.
if (_qdbusmenuWorkaround) {
connect(&_workaroundBatchTrayUpdate, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
_workaroundBatchTrayUpdate.setInterval(30 * 1000);
_workaroundBatchTrayUpdate.setSingleShot(true);
} else {
// Update the context menu whenever we're about to show it
// to the user.
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
// https://bugreports.qt.io/browse/QTBUG-54633 // https://bugreports.qt.io/browse/QTBUG-54633
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow())); _workaroundNoAboutToShowUpdate = true;
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide())); _workaroundManualVisibility = true;
#else
connect(_contextMenu.data(), &QMenu::aboutToShow, this, &ownCloudGui::updateContextMenu);
#endif #endif
#ifdef Q_OS_LINUX
// For KDE sessions if the platform plugin is missing,
// neither aboutToShow() updates nor the isVisible() call
// work. At least aboutToHide is reliable.
// https://github.com/owncloud/client/issues/6545
static QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
static QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
bool isKde =
xdgCurrentDesktop.contains("KDE")
|| desktopSession.contains("plasma")
|| desktopSession.contains("kde");
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
if (isKde && platformMenu && platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
_workaroundManualVisibility = true;
_workaroundNoAboutToShowUpdate = true;
} }
#endif
applyEnvVariable(&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate());
applyEnvVariable(&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick());
applyEnvVariable(&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray());
applyEnvVariable(&_workaroundManualVisibility, envForceWorkaroundManualVisibility());
qCInfo(lcApplication) << "Tray menu workarounds:"
<< "noabouttoshow:" << _workaroundNoAboutToShowUpdate
<< "fakedoubleclick:" << _workaroundFakeDoubleClick
<< "showhide:" << _workaroundShowAndHideTray
<< "manualvisibility:" << _workaroundManualVisibility;
connect(&_delayedTrayUpdateTimer, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
_delayedTrayUpdateTimer.setInterval(2 * 1000);
_delayedTrayUpdateTimer.setSingleShot(true);
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
// unfortunately aboutToHide is unreliable, it seems to work on OSX though
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
// Populate the context menu now. // Populate the context menu now.
updateContextMenu(); updateContextMenu();
@@ -510,13 +545,21 @@ void ownCloudGui::updateContextMenu()
return; return;
} }
if (_qdbusmenuWorkaround) { // If it's visible, we can't update live, and it won't be updated lazily: reschedule
if (contextMenuVisible() && !updateWhileVisible() && _workaroundNoAboutToShowUpdate) {
if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
}
if (_workaroundShowAndHideTray) {
// To make tray menu updates work with these bugs (see setupContextMenu) // To make tray menu updates work with these bugs (see setupContextMenu)
// we need to hide and show the tray icon. We don't want to do that // we need to hide and show the tray icon. We don't want to do that
// while it's visible! // while it's visible!
if (contextMenuVisible()) { if (contextMenuVisible()) {
if (!_workaroundBatchTrayUpdate.isActive()) { if (!_delayedTrayUpdateTimer.isActive()) {
_workaroundBatchTrayUpdate.start(); _delayedTrayUpdateTimer.start();
} }
return; return;
} }
@@ -631,35 +674,30 @@ void ownCloudGui::updateContextMenu()
} }
_contextMenu->addAction(_actionQuit); _contextMenu->addAction(_actionQuit);
if (_qdbusmenuWorkaround) { if (_workaroundShowAndHideTray) {
_tray->show(); _tray->show();
} }
} }
void ownCloudGui::updateContextMenuNeeded() void ownCloudGui::updateContextMenuNeeded()
{ {
// For the workaround case updating while visible is impossible. Instead // if it's visible and we can update live: update now
// occasionally update the menu when it's invisible. if (contextMenuVisible() && updateWhileVisible()) {
if (_qdbusmenuWorkaround) { // Note: don't update while visible on OSX
if (!_workaroundBatchTrayUpdate.isActive()) { // https://bugreports.qt.io/browse/QTBUG-54845
_workaroundBatchTrayUpdate.start(); updateContextMenu();
}
return; return;
} }
#ifdef Q_OS_MAC // if we can't lazily update: update later
// https://bugreports.qt.io/browse/QTBUG-54845 if (_workaroundNoAboutToShowUpdate) {
// We cannot update on demand or while visible -> update when invisible. // Note: don't update immediately even in the invisible case
if (!contextMenuVisible()) { // as that can lead to extremely frequent menu updates
updateContextMenu(); if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
} }
#else
if (updateWhileVisible() && contextMenuVisible())
updateContextMenu();
#endif
// If no update was done here, we might update it on-demand due to
// the aboutToShow() signal.
} }
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg) void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)

View File

@@ -119,14 +119,19 @@ private:
// tray's menu // tray's menu
QScopedPointer<QMenu> _contextMenu; QScopedPointer<QMenu> _contextMenu;
// Manually tracking whether the context menu is visible, but only works // Manually tracking whether the context menu is visible via aboutToShow
// on OSX because aboutToHide is not reliable everywhere. // and aboutToHide. Unfortunately aboutToHide isn't reliable everywhere
bool _contextMenuVisibleOsx; // so this only gets used with _workaroundManualVisibility (when the tray's
// isVisible() is unreliable)
bool _contextMenuVisibleManual = false;
QMenu *_recentActionsMenu; QMenu *_recentActionsMenu;
QVector<QMenu *> _accountMenus; QVector<QMenu *> _accountMenus;
bool _qdbusmenuWorkaround; bool _workaroundShowAndHideTray = false;
QTimer _workaroundBatchTrayUpdate; bool _workaroundNoAboutToShowUpdate = false;
bool _workaroundFakeDoubleClick = false;
bool _workaroundManualVisibility = false;
QTimer _delayedTrayUpdateTimer;
QMap<QString, QPointer<ShareDialog>> _shareDialogs; QMap<QString, QPointer<ShareDialog>> _shareDialogs;
QAction *_actionLogin; QAction *_actionLogin;

View File

@@ -183,6 +183,10 @@ SocketApi::SocketApi(QObject *parent)
// Example for developer builds (with ad-hoc signing identity): "" "com.owncloud.desktopclient" ".socketApi" // Example for developer builds (with ad-hoc signing identity): "" "com.owncloud.desktopclient" ".socketApi"
// Example for official signed packages: "9B5WD74GWJ." "com.owncloud.desktopclient" ".socketApi" // Example for official signed packages: "9B5WD74GWJ." "com.owncloud.desktopclient" ".socketApi"
socketPath = SOCKETAPI_TEAM_IDENTIFIER_PREFIX APPLICATION_REV_DOMAIN ".socketApi"; socketPath = SOCKETAPI_TEAM_IDENTIFIER_PREFIX APPLICATION_REV_DOMAIN ".socketApi";
#ifdef Q_OS_MAC
// Tell Finder to use the Extension (checking it from System Preferences -> Extensions)
system("pluginkit -e use -i " APPLICATION_REV_DOMAIN ".FinderSyncExt &");
#endif
} else if (Utility::isLinux() || Utility::isBSD()) { } else if (Utility::isLinux() || Utility::isBSD()) {
QString runtimeDir; QString runtimeDir;
runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
@@ -220,6 +224,11 @@ SocketApi::~SocketApi()
// All remaining sockets will be destroyed with _localServer, their parent // All remaining sockets will be destroyed with _localServer, their parent
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer); ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
_listeners.clear(); _listeners.clear();
#ifdef Q_OS_MAC
// Unload the extension (uncheck from System Preferences -> Extensions)
system("pluginkit -e ignore -i " APPLICATION_REV_DOMAIN ".FinderSyncExt &");
#endif
} }
void SocketApi::slotNewConnection() void SocketApi::slotNewConnection()

View File

@@ -204,6 +204,10 @@ void SslButton::slotUpdateMenu()
AccountPtr account = _accountState->account(); AccountPtr account = _accountState->account();
if (account->isHttp2Supported()) {
_menu->addAction("HTTP/2")->setEnabled(false);
}
if (account->url().scheme() == QLatin1String("https")) { if (account->url().scheme() == QLatin1String("https")) {
QString sslVersion = account->_sessionCipher.protocolString() QString sslVersion = account->_sessionCipher.protocolString()
+ ", " + account->_sessionCipher.authenticationMethod() + ", " + account->_sessionCipher.authenticationMethod()

View File

@@ -92,6 +92,11 @@ OCUpdater::OCUpdater(const QUrl &url)
{ {
} }
void OCUpdater::setUpdateUrl(const QUrl &url)
{
_updateUrl = url;
}
bool OCUpdater::performUpdate() bool OCUpdater::performUpdate()
{ {
ConfigFile cfg; ConfigFile cfg;
@@ -179,6 +184,81 @@ void OCUpdater::setDownloadState(DownloadState state)
} }
} }
#if defined(Q_OS_WIN)
// Following functions are taken from https://github.com/qt/qtbase/blob/5.8/src/corelib/io/qprocess_win.cpp
// to make use of this fix https://github.com/qt/qtbase/commit/bec2fc19fd18768b16925597871c77a61e716abd
// for QTBUG-53833: Without this we get an ugly powershell window on update. In 2.5/master we use Qt 5.10
// which obviously already has the fix.
static QString qt_create_commandline(const QString &program, const QStringList &arguments)
{
QString args;
if (!program.isEmpty()) {
QString programName = program;
if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1Char(' ')))
programName = QLatin1Char('\"') + programName + QLatin1Char('\"');
programName.replace(QLatin1Char('/'), QLatin1Char('\\'));
// add the prgram as the first arg ... it works better
args = programName + QLatin1Char(' ');
}
for (int i=0; i<arguments.size(); ++i) {
QString tmp = arguments.at(i);
// Quotes are escaped and their preceding backslashes are doubled.
tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
int i = tmp.length();
while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\'))
--i;
tmp.insert(i, QLatin1Char('"'));
tmp.prepend(QLatin1Char('"'));
}
args += QLatin1Char(' ') + tmp;
}
return args;
}
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDir = QString(), qint64 *pid = 0)
{
// static const DWORD errorElevationRequired = 740;
QString args = qt_create_commandline(program, arguments);
bool success = false;
PROCESS_INFORMATION pinfo;
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
success = CreateProcess(0, (wchar_t*)args.utf16(),
0, 0, FALSE, dwCreationFlags, 0,
workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
&startupInfo, &pinfo);
// if (success) {
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
if (pid)
*pid = pinfo.dwProcessId;
// } else if (GetLastError() == errorElevationRequired) {
// success = startDetachedUacPrompt(program, arguments, workingDir, pid);
// }
return success;
}
#else
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDir = QString(), qint64 *pid = 0)
{
return QProcess::startDetached(program, arguments, workingDir, pid);
}
#endif
void OCUpdater::slotStartInstaller() void OCUpdater::slotStartInstaller()
{ {
ConfigFile cfg; ConfigFile cfg;
@@ -187,8 +267,30 @@ void OCUpdater::slotStartInstaller()
settings.setValue(autoUpdateAttemptedC, true); settings.setValue(autoUpdateAttemptedC, true);
settings.sync(); settings.sync();
qCInfo(lcUpdater) << "Running updater" << updateFile; qCInfo(lcUpdater) << "Running updater" << updateFile;
QProcess::startDetached(updateFile, QStringList() << "/S"
<< "/launch"); if(updateFile.endsWith(".exe")) {
QProcess::startDetached(updateFile, QStringList() << "/S"
<< "/launch");
} else if(updateFile.endsWith(".msi")) {
// When MSIs are installed without gui they cannot launch applications
// as they lack the user context. That is why we need to run the client
// manually here. We wrap the msiexec and client invocation in a powershell
// script because owncloud.exe will be shut down for installation.
// | Out-Null forces powershell to wait for msiexec to finish.
auto preparePathForPowershell = [](QString path) {
path.replace("'", "''");
return QDir::toNativeSeparators(path);
};
auto msiLogFile = cfg.configPath() + "msi.log";
QString command = QString("&{msiexec /norestart /passive /i '%1' /L*V '%2'| Out-Null ; &'%3'}")
.arg(preparePathForPowershell(updateFile))
.arg(preparePathForPowershell(msiLogFile))
.arg(preparePathForPowershell(QCoreApplication::applicationFilePath()));
startDetached("powershell.exe", QStringList{"-Command", command});
}
} }
void OCUpdater::checkForUpdate() void OCUpdater::checkForUpdate()
@@ -298,7 +400,7 @@ void NSISUpdater::versionInfoArrived(const UpdateInfo &info)
showDialog(info); showDialog(info);
} }
if (!url.isEmpty()) { if (!url.isEmpty()) {
_targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')); _targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')+1);
if (QFile(_targetFile).exists()) { if (QFile(_targetFile).exists()) {
setDownloadState(DownloadComplete); setDownloadState(DownloadComplete);
} else { } else {

View File

@@ -99,6 +99,8 @@ public:
UpdateOnlyAvailableThroughSystem }; UpdateOnlyAvailableThroughSystem };
explicit OCUpdater(const QUrl &url); explicit OCUpdater(const QUrl &url);
void setUpdateUrl(const QUrl &url);
bool performUpdate(); bool performUpdate();
void checkForUpdate() Q_DECL_OVERRIDE; void checkForUpdate() Q_DECL_OVERRIDE;

View File

@@ -23,15 +23,20 @@ namespace OCC {
class SparkleUpdater : public Updater class SparkleUpdater : public Updater
{ {
Q_OBJECT
public: public:
SparkleUpdater(const QString &appCastUrl); SparkleUpdater(const QUrl &appCastUrl);
~SparkleUpdater(); ~SparkleUpdater();
void setUpdateUrl(const QUrl &url);
// unused in this updater // unused in this updater
void checkForUpdate() Q_DECL_OVERRIDE; void checkForUpdate() Q_DECL_OVERRIDE;
void backgroundCheckForUpdate() Q_DECL_OVERRIDE; void backgroundCheckForUpdate() Q_DECL_OVERRIDE;
bool handleStartup() Q_DECL_OVERRIDE { return false; } bool handleStartup() Q_DECL_OVERRIDE { return false; }
QString statusString();
private: private:
class Private; class Private;
Private *d; Private *d;

View File

@@ -73,7 +73,7 @@ class SparkleUpdater::Private
}; };
// Delete ~/Library//Preferences/com.owncloud.desktopclient.plist to re-test // Delete ~/Library//Preferences/com.owncloud.desktopclient.plist to re-test
SparkleUpdater::SparkleUpdater(const QString& appCastUrl) SparkleUpdater::SparkleUpdater(const QUrl& appCastUrl)
: Updater() : Updater()
{ {
d = new Private; d = new Private;
@@ -89,9 +89,7 @@ SparkleUpdater::SparkleUpdater(const QString& appCastUrl)
[d->updater resetUpdateCycle]; [d->updater resetUpdateCycle];
[d->updater retain]; [d->updater retain];
NSURL* url = [NSURL URLWithString: setUpdateUrl(appCastUrl);
[NSString stringWithUTF8String: appCastUrl.toUtf8().data()]];
[d->updater setFeedURL: url];
// Sparkle 1.8 required // Sparkle 1.8 required
NSString *userAgent = [NSString stringWithUTF8String: Utility::userAgentString().data()]; NSString *userAgent = [NSString stringWithUTF8String: Utility::userAgentString().data()];
@@ -104,7 +102,14 @@ SparkleUpdater::~SparkleUpdater()
delete d; delete d;
} }
void SparkleUpdater::setUpdateUrl(const QUrl &url)
{
NSURL* nsurl = [NSURL URLWithString:
[NSString stringWithUTF8String: url.toString().toUtf8().data()]];
[d->updater setFeedURL: nsurl];
}
// FIXME: Should be changed to not instanicate the SparkleUpdater at all in this case
bool autoUpdaterAllowed() bool autoUpdaterAllowed()
{ {
// See https://github.com/owncloud/client/issues/2931 // See https://github.com/owncloud/client/issues/2931
@@ -133,4 +138,10 @@ void SparkleUpdater::backgroundCheckForUpdate()
} }
} }
QString SparkleUpdater::statusString()
{
// FIXME Show the real state depending on the callbacks
return QString();
}
} // namespace OCC } // namespace OCC

View File

@@ -22,6 +22,7 @@
#include "theme.h" #include "theme.h"
#include "common/utility.h" #include "common/utility.h"
#include "version.h" #include "version.h"
#include "configfile.h"
#include "config.h" #include "config.h"
@@ -39,6 +40,29 @@ Updater *Updater::instance()
return _instance; return _instance;
} }
QUrl Updater::updateUrl()
{
QUrl updateBaseUrl(QString::fromLocal8Bit(qgetenv("OCC_UPDATE_URL")));
if (updateBaseUrl.isEmpty()) {
updateBaseUrl = QUrl(QLatin1String(APPLICATION_UPDATE_URL));
}
if (!updateBaseUrl.isValid() || updateBaseUrl.host() == ".") {
return QUrl();
}
auto url = addQueryParams(updateBaseUrl);
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
url.addQueryItem(QLatin1String("sparkle"), QLatin1String("true"));
#endif
#if defined(Q_OS_WIN)
url.addQueryItem(QLatin1String("msi"), QLatin1String("true"));
#endif
return url;
}
QUrl Updater::addQueryParams(const QUrl &url) QUrl Updater::addQueryParams(const QUrl &url)
{ {
QUrl paramUrl = url; QUrl paramUrl = url;
@@ -64,14 +88,10 @@ QUrl Updater::addQueryParams(const QUrl &url)
QString suffix = QString::fromLatin1(MIRALL_STRINGIFY(MIRALL_VERSION_SUFFIX)); QString suffix = QString::fromLatin1(MIRALL_STRINGIFY(MIRALL_VERSION_SUFFIX));
paramUrl.addQueryItem(QLatin1String("versionsuffix"), suffix); paramUrl.addQueryItem(QLatin1String("versionsuffix"), suffix);
if (suffix.startsWith("daily")
|| suffix.startsWith("nightly") auto channel = ConfigFile().updateChannel();
|| suffix.startsWith("alpha") if (channel != "stable") {
|| suffix.startsWith("rc") paramUrl.addQueryItem(QLatin1String("channel"), channel);
|| suffix.startsWith("beta")) {
paramUrl.addQueryItem(QLatin1String("channel"), "beta");
// FIXME: Provide a checkbox in UI to enable regular versions to switch
// to beta channel
} }
return paramUrl; return paramUrl;
@@ -98,23 +118,18 @@ QString Updater::getSystemInfo()
// To test, cmake with -DAPPLICATION_UPDATE_URL="http://127.0.0.1:8080/test.rss" // To test, cmake with -DAPPLICATION_UPDATE_URL="http://127.0.0.1:8080/test.rss"
Updater *Updater::create() Updater *Updater::create()
{ {
QUrl updateBaseUrl(QString::fromLocal8Bit(qgetenv("OCC_UPDATE_URL"))); auto url = updateUrl();
if (updateBaseUrl.isEmpty()) { if (url.isEmpty()) {
updateBaseUrl = QUrl(QLatin1String(APPLICATION_UPDATE_URL));
}
if (!updateBaseUrl.isValid() || updateBaseUrl.host() == ".") {
qCWarning(lcUpdater) << "Not a valid updater URL, will not do update check"; qCWarning(lcUpdater) << "Not a valid updater URL, will not do update check";
return 0; return 0;
} }
updateBaseUrl = addQueryParams(updateBaseUrl);
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE) #if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
updateBaseUrl.addQueryItem(QLatin1String("sparkle"), QLatin1String("true")); return new SparkleUpdater(url);
return new SparkleUpdater(updateBaseUrl.toString());
#elif defined(Q_OS_WIN32) #elif defined(Q_OS_WIN32)
// the best we can do is notify about updates // the best we can do is notify about updates
return new NSISUpdater(updateBaseUrl); return new NSISUpdater(url);
#else #else
return new PassiveUpdateNotifier(QUrl(updateBaseUrl)); return new PassiveUpdateNotifier(url);
#endif #endif
} }

View File

@@ -36,6 +36,7 @@ public:
}; };
static Updater *instance(); static Updater *instance();
static QUrl updateUrl();
virtual void checkForUpdate() = 0; virtual void checkForUpdate() = 0;
virtual void backgroundCheckForUpdate() = 0; virtual void backgroundCheckForUpdate() = 0;

View File

@@ -218,7 +218,7 @@ public:
/** Detects a specific bug in older server versions */ /** Detects a specific bug in older server versions */
bool rootEtagChangesNotOnlySubFolderEtags(); bool rootEtagChangesNotOnlySubFolderEtags();
/** True when the server supports HTTP2 */ /** True when the server connection is using HTTP2 */
bool isHttp2Supported() { return _http2Supported; } bool isHttp2Supported() { return _http2Supported; }
void setHttp2Supported(bool value) { _http2Supported = value; } void setHttp2Supported(bool value) { _http2Supported = value; }

View File

@@ -18,6 +18,7 @@
#include "theme.h" #include "theme.h"
#include "common/utility.h" #include "common/utility.h"
#include "common/asserts.h" #include "common/asserts.h"
#include "version.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
@@ -52,6 +53,7 @@ static const char crashReporterC[] = "crashReporter";
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications"; static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
static const char skipUpdateCheckC[] = "skipUpdateCheck"; static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char updateCheckIntervalC[] = "updateCheckInterval"; static const char updateCheckIntervalC[] = "updateCheckInterval";
static const char updateChannelC[] = "updateChannel";
static const char geometryC[] = "geometry"; static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout"; static const char timeoutC[] = "timeout";
static const char chunkSizeC[] = "chunkSize"; static const char chunkSizeC[] = "chunkSize";
@@ -468,6 +470,28 @@ void ConfigFile::setSkipUpdateCheck(bool skip, const QString &connection)
settings.sync(); settings.sync();
} }
QString ConfigFile::updateChannel() const
{
QString defaultUpdateChannel = QStringLiteral("stable");
QString suffix = QString::fromLatin1(MIRALL_STRINGIFY(MIRALL_VERSION_SUFFIX));
if (suffix.startsWith("daily")
|| suffix.startsWith("nightly")
|| suffix.startsWith("alpha")
|| suffix.startsWith("rc")
|| suffix.startsWith("beta")) {
defaultUpdateChannel = QStringLiteral("beta");
}
QSettings settings(configFile(), QSettings::IniFormat);
return settings.value(QLatin1String(updateChannelC), defaultUpdateChannel).toString();
}
void ConfigFile::setUpdateChannel(const QString &channel)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setValue(QLatin1String(updateChannelC), channel);
}
int ConfigFile::maxLogLines() const int ConfigFile::maxLogLines() const
{ {
QSettings settings(configFile(), QSettings::IniFormat); QSettings settings(configFile(), QSettings::IniFormat);

View File

@@ -131,6 +131,9 @@ public:
bool skipUpdateCheck(const QString &connection = QString()) const; bool skipUpdateCheck(const QString &connection = QString()) const;
void setSkipUpdateCheck(bool, const QString &); void setSkipUpdateCheck(bool, const QString &);
QString updateChannel() const;
void setUpdateChannel(const QString &channel);
void saveGeometryHeader(QHeaderView *header); void saveGeometryHeader(QHeaderView *header);
void restoreGeometryHeader(QHeaderView *header); void restoreGeometryHeader(QHeaderView *header);

View File

@@ -117,6 +117,7 @@ HttpCredentials::HttpCredentials(const QString &user, const QString &password, c
, _clientSslKey(key) , _clientSslKey(key)
, _clientSslCertificate(certificate) , _clientSslCertificate(certificate)
, _keychainMigration(false) , _keychainMigration(false)
, _retryOnKeyChainError(false)
{ {
} }
@@ -219,6 +220,21 @@ void HttpCredentials::deleteOldKeychainEntries()
void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incoming) void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incoming)
{ {
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
Q_ASSERT(!incoming->insecureFallback()); // If insecureFallback is set, the next test would be pointless
if (_retryOnKeyChainError && (incoming->error() == QKeychain::NoBackendAvailable
|| incoming->error() == QKeychain::OtherError)) {
// Could be that the backend was not yet available. Wait some extra seconds.
// (Issues #4274 and #6522)
// (For kwallet, the error is OtherError instead of NoBackendAvailable, maybe a bug in QtKeychain)
qCInfo(lcHttpCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << incoming->errorString();
QTimer::singleShot(10000, this, &HttpCredentials::fetchFromKeychainHelper);
_retryOnKeyChainError = false;
return;
}
_retryOnKeyChainError = false;
#endif
// Store PEM in memory // Store PEM in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming); ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) { if (readJob->error() == NoError && readJob->binaryData().length() > 0) {

View File

@@ -141,6 +141,7 @@ protected:
QSslKey _clientSslKey; QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate; QSslCertificate _clientSslCertificate;
bool _keychainMigration; bool _keychainMigration;
bool _retryOnKeyChainError = true; // true if we haven't done yet any reading from keychain
}; };

View File

@@ -579,8 +579,7 @@ bool OwncloudPropagator::localFileNameClash(const QString &relFile)
re = false; re = false;
qCWarning(lcPropagator) << "No valid fileinfo"; qCWarning(lcPropagator) << "No valid fileinfo";
} else { } else {
// Need to normalize to composited form because of // Need to normalize to composited form because of QTBUG-39622/QTBUG-55896
// https://bugreports.qt-project.org/browse/QTBUG-39622
const QString cName = fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_C); const QString cName = fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_C);
bool equal = (file == cName); bool equal = (file == cName);
re = (!equal && !cName.endsWith(relFile, Qt::CaseSensitive)); re = (!equal && !cName.endsWith(relFile, Qt::CaseSensitive));
@@ -821,10 +820,13 @@ void PropagatorCompositeJob::slotSubJobFinished(SyncFileItem::Status status)
ASSERT(i >= 0); ASSERT(i >= 0);
_runningJobs.remove(i); _runningJobs.remove(i);
// Any sub job error will cause the whole composite to fail. This is important
// for knowing whether to update the etag in PropagateDirectory, for example.
if (status == SyncFileItem::FatalError if (status == SyncFileItem::FatalError
|| status == SyncFileItem::NormalError || status == SyncFileItem::NormalError
|| status == SyncFileItem::SoftError || status == SyncFileItem::SoftError
|| status == SyncFileItem::DetailError) { || status == SyncFileItem::DetailError
|| status == SyncFileItem::BlacklistedError) {
_hasError = status; _hasError = status;
} }

View File

@@ -553,6 +553,16 @@ void PropagateUploadFileCommon::commonErrorHandling(AbstractNetworkJob *job)
abortWithError(status, errorString); abortWithError(status, errorString);
} }
void PropagateUploadFileCommon::adjustLastJobTimeout(AbstractNetworkJob *job, quint64 fileSize)
{
job->setTimeout(qBound(
job->timeoutMsec(),
// Calculate 3 minutes for each gigabyte of data
qint64((3 * 60 * 1000) * fileSize / 1e9),
// Maximum of 30 minutes
qint64(30 * 60 * 1000)));
}
void PropagateUploadFileCommon::slotJobDestroyed(QObject *job) void PropagateUploadFileCommon::slotJobDestroyed(QObject *job)
{ {
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job), _jobs.end()); _jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job), _jobs.end());

View File

@@ -281,6 +281,17 @@ protected:
*/ */
void commonErrorHandling(AbstractNetworkJob *job); void commonErrorHandling(AbstractNetworkJob *job);
/**
* Increases the timeout for the final MOVE/PUT for large files.
*
* This is an unfortunate workaround since the drawback is not being able to
* detect real disconnects in a timely manner. Shall go away when the server
* response starts coming quicker, or there is some sort of async api.
*
* See #6527, enterprise#2480
*/
static void adjustLastJobTimeout(AbstractNetworkJob *job, quint64 fileSize);
// Bases headers that need to be sent with every chunk // Bases headers that need to be sent with every chunk
QMap<QByteArray, QByteArray> headers(); QMap<QByteArray, QByteArray> headers();
}; };

View File

@@ -295,6 +295,7 @@ void PropagateUploadFileNG::startNextChunk()
connect(job, &MoveJob::finishedSignal, this, &PropagateUploadFileNG::slotMoveJobFinished); connect(job, &MoveJob::finishedSignal, this, &PropagateUploadFileNG::slotMoveJobFinished);
connect(job, &QObject::destroyed, this, &PropagateUploadFileCommon::slotJobDestroyed); connect(job, &QObject::destroyed, this, &PropagateUploadFileCommon::slotJobDestroyed);
propagator()->_activeJobList.append(this); propagator()->_activeJobList.append(this);
adjustLastJobTimeout(job, fileSize);
job->start(); job->start();
return; return;
} }

View File

@@ -130,6 +130,8 @@ void PropagateUploadFileV1::startNextChunk()
connect(job, &PUTFileJob::uploadProgress, this, &PropagateUploadFileV1::slotUploadProgress); connect(job, &PUTFileJob::uploadProgress, this, &PropagateUploadFileV1::slotUploadProgress);
connect(job, &PUTFileJob::uploadProgress, device, &UploadDevice::slotJobUploadProgress); connect(job, &PUTFileJob::uploadProgress, device, &UploadDevice::slotJobUploadProgress);
connect(job, &QObject::destroyed, this, &PropagateUploadFileCommon::slotJobDestroyed); connect(job, &QObject::destroyed, this, &PropagateUploadFileCommon::slotJobDestroyed);
if (isFinalChunk)
adjustLastJobTimeout(job, fileSize);
job->start(); job->start();
propagator()->_activeJobList.append(this); propagator()->_activeJobList.append(this);
_currentChunk++; _currentChunk++;
@@ -301,6 +303,7 @@ void PropagateUploadFileV1::slotPutFinished()
qCWarning(lcPropagateUpload) << "Server does not support X-OC-MTime" << job->reply()->rawHeader("X-OC-MTime"); qCWarning(lcPropagateUpload) << "Server does not support X-OC-MTime" << job->reply()->rawHeader("X-OC-MTime");
// Well, the mtime was not set // Well, the mtime was not set
done(SyncFileItem::SoftError, "Server does not support X-OC-MTime"); done(SyncFileItem::SoftError, "Server does not support X-OC-MTime");
return;
} }
#ifdef WITH_TESTING #ifdef WITH_TESTING

View File

@@ -82,10 +82,9 @@ public:
/** For files whose errors were blacklisted /** For files whose errors were blacklisted
* *
* If an file is blacklisted due to an error it isn't even reattempted. These * If an file is blacklisted due to an error it isn't even reattempted. These
* errors should appear in the issues tab, but not on the account settings and * errors should appear in the issues tab but should be silent otherwise.
* should not cause the sync run to fail.
* *
* A DetailError that doesn't cause sync failure. * A SoftError caused by blacklisting.
*/ */
BlacklistedError BlacklistedError
}; };

View File

@@ -576,6 +576,51 @@ private slots:
//QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); //QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
} }
} }
// https://github.com/owncloud/client/issues/6629#issuecomment-402450691
// When a file is moved and the server mtime was not in sync, the local mtime should be kept
void testMoveAndMTimeChange()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
int nPUT = 0;
int nDELETE = 0;
int nGET = 0;
int nMOVE = 0;
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &req) {
if (op == QNetworkAccessManager::PutOperation)
++nPUT;
if (op == QNetworkAccessManager::DeleteOperation)
++nDELETE;
if (op == QNetworkAccessManager::GetOperation)
++nGET;
if (req.attribute(QNetworkRequest::CustomVerbAttribute) == "MOVE")
++nMOVE;
return nullptr;
});
// Changing the mtime on the server (without invalidating the etag)
fakeFolder.remoteModifier().find("A/a1")->lastModified = QDateTime::currentDateTimeUtc().addSecs(-50000);
fakeFolder.remoteModifier().find("A/a2")->lastModified = QDateTime::currentDateTimeUtc().addSecs(-40000);
// Move a few files
fakeFolder.remoteModifier().rename("A/a1", "A/a1_server_renamed");
fakeFolder.localModifier().rename("A/a2", "A/a2_local_renamed");
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nGET, 0);
QCOMPARE(nPUT, 0);
QCOMPARE(nMOVE, 1);
QCOMPARE(nDELETE, 0);
// Another sync should do nothing
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nGET, 0);
QCOMPARE(nPUT, 0);
QCOMPARE(nMOVE, 1);
QCOMPARE(nDELETE, 0);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
}
}; };
QTEST_GUILESS_MAIN(TestSyncMove) QTEST_GUILESS_MAIN(TestSyncMove)

View File

@@ -373,7 +373,7 @@
<message> <message>
<location filename="../src/gui/accountstate.cpp" line="132"/> <location filename="../src/gui/accountstate.cpp" line="132"/>
<source>Maintenance mode</source> <source>Maintenance mode</source>
<translation type="unfinished"/> <translation>Mode de manteniment</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountstate.cpp" line="134"/> <location filename="../src/gui/accountstate.cpp" line="134"/>
@@ -1415,12 +1415,12 @@ Els elements que poden ser eliminats s&apos;eliminaran si impedeixen que una car
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="73"/> <location filename="../src/gui/issueswidget.ui" line="73"/>
<source>Show warnings</source> <source>Show warnings</source>
<translation type="unfinished"/> <translation>Mostra avisos</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="83"/> <location filename="../src/gui/issueswidget.ui" line="83"/>
<source>Show ignored files</source> <source>Show ignored files</source>
<translation type="unfinished"/> <translation>Mostra arxius descartats</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="133"/> <location filename="../src/gui/issueswidget.ui" line="133"/>
@@ -2507,7 +2507,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/servernotificationhandler.cpp" line="103"/> <location filename="../src/gui/servernotificationhandler.cpp" line="103"/>
<source>Dismiss</source> <source>Dismiss</source>
<translation type="unfinished"/> <translation>Ignora</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -2622,12 +2622,12 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/sharedialog.cpp" line="211"/> <location filename="../src/gui/sharedialog.cpp" line="211"/>
<source>Users and Groups</source> <source>Users and Groups</source>
<translation type="unfinished"/> <translation>Usuaris i Grups</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharedialog.cpp" line="218"/> <location filename="../src/gui/sharedialog.cpp" line="218"/>
<source>Public Links</source> <source>Public Links</source>
<translation type="unfinished"/> <translation>Enllaços públics</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -2650,7 +2650,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="35"/> <location filename="../src/gui/sharelinkwidget.ui" line="35"/>
<source>Enter a name to create a new public link...</source> <source>Enter a name to create a new public link...</source>
<translation type="unfinished"/> <translation>Escriu un nom per crear un enllaç públic...</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="42"/> <location filename="../src/gui/sharelinkwidget.ui" line="42"/>
@@ -2670,12 +2670,12 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="178"/> <location filename="../src/gui/sharelinkwidget.ui" line="178"/>
<source>Link properties:</source> <source>Link properties:</source>
<translation type="unfinished"/> <translation>Propietats de l&apos;enllaç:</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="220"/> <location filename="../src/gui/sharelinkwidget.ui" line="220"/>
<source>Show file listing</source> <source>Show file listing</source>
<translation type="unfinished"/> <translation>Motra el llistat de fitxers</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="200"/> <location filename="../src/gui/sharelinkwidget.ui" line="200"/>
@@ -2685,7 +2685,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="20"/> <location filename="../src/gui/sharelinkwidget.ui" line="20"/>
<source>Anyone with the link has access to the file/folder</source> <source>Anyone with the link has access to the file/folder</source>
<translation type="unfinished"/> <translation>Qualsevol podrà accedir a l&apos;arxiu o carpeta amb aquest link</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="117"/> <location filename="../src/gui/sharelinkwidget.cpp" line="117"/>
@@ -2727,7 +2727,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="164"/> <location filename="../src/gui/sharelinkwidget.cpp" line="164"/>
<source>Copy link to clipboard</source> <source>Copy link to clipboard</source>
<translation type="unfinished"/> <translation>Copiar al portadocuments</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="165"/> <location filename="../src/gui/sharelinkwidget.cpp" line="165"/>
@@ -2763,7 +2763,7 @@ No és aconsellada usar-la.</translation>
<location filename="../src/gui/sharelinkwidget.cpp" line="63"/> <location filename="../src/gui/sharelinkwidget.cpp" line="63"/>
<location filename="../src/gui/sharelinkwidget.cpp" line="543"/> <location filename="../src/gui/sharelinkwidget.cpp" line="543"/>
<source>Public link</source> <source>Public link</source>
<translation type="unfinished"/> <translation>Enllaç públic</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="253"/> <location filename="../src/gui/sharelinkwidget.cpp" line="253"/>
@@ -2811,7 +2811,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="237"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="237"/>
<source>Copy link to clipboard</source> <source>Copy link to clipboard</source>
<translation type="unfinished"/> <translation>Copiar al portadocuments</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="239"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="239"/>
@@ -2826,7 +2826,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="337"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="337"/>
<source>I shared something with you</source> <source>I shared something with you</source>
<translation type="unfinished"/> <translation>He compartit amb tu</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -2919,7 +2919,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/socketapi.cpp" line="557"/> <location filename="../src/gui/socketapi.cpp" line="557"/>
<source>I shared something with you</source> <source>I shared something with you</source>
<translation type="unfinished"/> <translation>He compartit amb tu</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/socketapi.cpp" line="565"/> <location filename="../src/gui/socketapi.cpp" line="565"/>
@@ -3850,7 +3850,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/>
<source>Re-open Browser</source> <source>Re-open Browser</source>
<translation type="unfinished"/> <translation>Reobrir navegador</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -4177,7 +4177,7 @@ No és aconsellada usar-la.</translation>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="33"/> <location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source> <source>Could not open browser</source>
<translation type="unfinished"/> <translation>No es pot obrir el navegador</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="34"/> <location filename="../src/gui/guiutility.cpp" line="34"/>

View File

@@ -83,12 +83,12 @@
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source> <source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/> <translation>Neznámá chyba: odpověď sítě byla smazána</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
<source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source> <source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source>
<translation type="unfinished"/> <translation>Odpověď serveru &quot;%1 %2&quot; do &quot;%3 %4&quot;</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -388,7 +388,7 @@
<message> <message>
<location filename="../src/gui/accountstate.cpp" line="138"/> <location filename="../src/gui/accountstate.cpp" line="138"/>
<source>Asking Credentials</source> <source>Asking Credentials</source>
<translation type="unfinished"/> <translation>Požádat o pověření</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountstate.cpp" line="140"/> <location filename="../src/gui/accountstate.cpp" line="140"/>
@@ -988,7 +988,7 @@ Pokračováním v synchronizaci způsobí přepsání všech vašich souborů st
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="209"/> <location filename="../src/gui/folderstatusmodel.cpp" line="209"/>
<source>There are unresolved conflicts. Click for details.</source> <source>There are unresolved conflicts. Click for details.</source>
<translation type="unfinished"/> <translation>Jsou zde nevyřešené konflikty. Klikněte pro detaily.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="878"/> <location filename="../src/gui/folderstatusmodel.cpp" line="878"/>
@@ -1396,7 +1396,7 @@ Položky u kterých je povoleno smazání budou vymazány, pokud by bránily ods
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="20"/> <location filename="../src/gui/issueswidget.ui" line="20"/>
<source>List of issues</source> <source>List of issues</source>
<translation type="unfinished"/> <translation>Seznam problémů</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="34"/> <location filename="../src/gui/issueswidget.ui" line="34"/>
@@ -3628,12 +3628,12 @@ Nedoporučuje se jí používat.</translation>
<location filename="../src/gui/owncloudgui.cpp" line="273"/> <location filename="../src/gui/owncloudgui.cpp" line="273"/>
<location filename="../src/gui/owncloudgui.cpp" line="304"/> <location filename="../src/gui/owncloudgui.cpp" line="304"/>
<source>Synchronization is paused</source> <source>Synchronization is paused</source>
<translation type="unfinished"/> <translation>Synchronizace je pozastavena</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/owncloudgui.cpp" line="306"/> <location filename="../src/gui/owncloudgui.cpp" line="306"/>
<source>Error during synchronization</source> <source>Error during synchronization</source>
<translation type="unfinished"/> <translation>Chyba při synchronizaci</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/owncloudgui.cpp" line="314"/> <location filename="../src/gui/owncloudgui.cpp" line="314"/>
@@ -3843,17 +3843,17 @@ Nedoporučuje se jí používat.</translation>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="36"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="36"/>
<source>Please switch to your browser to proceed.</source> <source>Please switch to your browser to proceed.</source>
<translation type="unfinished"/> <translation>Chcete-li pokračovat, přepněte prosím do svého prohlížeče.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="46"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="46"/>
<source>An error occured while connecting. Please try again.</source> <source>An error occured while connecting. Please try again.</source>
<translation type="unfinished"/> <translation>Při připojování došlo k chybě. Prosím zkuste to znovu.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/>
<source>Re-open Browser</source> <source>Re-open Browser</source>
<translation type="unfinished"/> <translation>Znovu otevřít prohlížeč</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -4180,7 +4180,7 @@ Nedoporučuje se jí používat.</translation>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="33"/> <location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source> <source>Could not open browser</source>
<translation type="unfinished"/> <translation>Nemohu otevřít prohlížeč</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="34"/> <location filename="../src/gui/guiutility.cpp" line="34"/>

View File

@@ -60,12 +60,12 @@
<message> <message>
<location filename="../src/gui/notificationwidget.ui" line="56"/> <location filename="../src/gui/notificationwidget.ui" line="56"/>
<source>Lorem ipsum dolor sit amet</source> <source>Lorem ipsum dolor sit amet</source>
<translation type="unfinished"/> <translation>Lorem ipsum dolor sit amet</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/notificationwidget.ui" line="69"/> <location filename="../src/gui/notificationwidget.ui" line="69"/>
<source>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod temporm </source> <source>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod temporm </source>
<translation type="unfinished"/> <translation>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod temporm</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/notificationwidget.ui" line="89"/> <location filename="../src/gui/notificationwidget.ui" line="89"/>
@@ -83,7 +83,7 @@
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source> <source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/> <translation>Error desconocido: la respuesta de la red fue eliminada</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>

View File

@@ -83,12 +83,12 @@
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source> <source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
<source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source> <source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source>
<translation type="unfinished"/> <translation> &quot;%1 %2&quot; &quot;%3 %4&quot;</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -253,7 +253,7 @@
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="667"/> <location filename="../src/gui/accountsettings.cpp" line="667"/>
<source>Obtaining authorization from the browser. &lt;a href=&apos;%1&apos;&gt;Click here&lt;/a&gt; to re-open the browser.</source> <source>Obtaining authorization from the browser. &lt;a href=&apos;%1&apos;&gt;Click here&lt;/a&gt; to re-open the browser.</source>
<translation type="unfinished"/> <translation>&lt;a href=&apos;%1&apos;&gt;&lt;/a&gt; </translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="671"/> <location filename="../src/gui/accountsettings.cpp" line="671"/>
@@ -1428,12 +1428,12 @@ Items where deletion is allowed will be deleted if they prevent a directory from
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="133"/> <location filename="../src/gui/issueswidget.ui" line="133"/>
<source>There were too many issues. Not all will be visible here.</source> <source>There were too many issues. Not all will be visible here.</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="155"/> <location filename="../src/gui/issueswidget.ui" line="155"/>
<source>Copy the issues list to the clipboard.</source> <source>Copy the issues list to the clipboard.</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="158"/> <location filename="../src/gui/issueswidget.ui" line="158"/>
@@ -1693,7 +1693,7 @@ Items where deletion is allowed will be deleted if they prevent a directory from
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="112"/> <location filename="../src/gui/creds/oauth.cpp" line="112"/>
<source>Error returned from the server: &lt;em&gt;%1&lt;/em&gt;</source> <source>Error returned from the server: &lt;em&gt;%1&lt;/em&gt;</source>
<translation type="unfinished"/> <translation>: &lt;em&gt;%1&lt;/em&gt; </translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="115"/> <location filename="../src/gui/creds/oauth.cpp" line="115"/>
@@ -1708,17 +1708,17 @@ Items where deletion is allowed will be deleted if they prevent a directory from
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="121"/> <location filename="../src/gui/creds/oauth.cpp" line="121"/>
<source>The reply from the server did not contain all expected fields</source> <source>The reply from the server did not contain all expected fields</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="125"/> <location filename="../src/gui/creds/oauth.cpp" line="125"/>
<source>&lt;h1&gt;Login Error&lt;/h1&gt;&lt;p&gt;%1&lt;/p&gt;</source> <source>&lt;h1&gt;Login Error&lt;/h1&gt;&lt;p&gt;%1&lt;/p&gt;</source>
<translation type="unfinished"/> <translation>&lt;h1&gt;&lt;/h1&gt;&lt;p&gt;%1&lt;/p&gt; </translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="131"/> <location filename="../src/gui/creds/oauth.cpp" line="131"/>
<source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source> <source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source>
<translation type="unfinished"/> <translation>&lt;h1&gt;&lt;/h1&gt;&lt;p&gt;&lt;em&gt;%1&lt;/em&gt;&lt;em&gt;%2&lt;/em&gt;&lt;br&gt; %3 &lt;a href=&apos;%4&apos;&gt;&lt;/a&gt; %2 &lt;/p&gt; </translation>
</message> </message>
</context> </context>
<context> <context>
@@ -1885,7 +1885,7 @@ for additional privileges during the process.</source>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/>
<source>Login in your browser</source> <source>Login in your browser</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@@ -1962,7 +1962,7 @@ It is not advisable to use it.</source>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/>
<source>The server reported the following error:</source> <source>The server reported the following error:</source>
<translation type="unfinished"/> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/>
@@ -2723,12 +2723,12 @@ It is not advisable to use it.</source>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="163"/> <location filename="../src/gui/sharelinkwidget.cpp" line="163"/>
<source>Open link in browser</source> <source>Open link in browser</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="164"/> <location filename="../src/gui/sharelinkwidget.cpp" line="164"/>
<source>Copy link to clipboard</source> <source>Copy link to clipboard</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="165"/> <location filename="../src/gui/sharelinkwidget.cpp" line="165"/>
@@ -2807,12 +2807,12 @@ It is not advisable to use it.</source>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="235"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="235"/>
<source>Open link in browser</source> <source>Open link in browser</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="237"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="237"/>
<source>Copy link to clipboard</source> <source>Copy link to clipboard</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="239"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="239"/>
@@ -4178,12 +4178,12 @@ It is not advisable to use it.</source>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="33"/> <location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source> <source>Could not open browser</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="34"/> <location filename="../src/gui/guiutility.cpp" line="34"/>
<source>There was an error when launching the browser to go to URL %1. Maybe no default browser is configured?</source> <source>There was an error when launching the browser to go to URL %1. Maybe no default browser is configured?</source>
<translation type="unfinished"/> <translation>URL %1 </translation>
</message> </message>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="55"/> <location filename="../src/gui/guiutility.cpp" line="55"/>

View File

@@ -1720,7 +1720,7 @@ Elementer hvor sletting er tillatt, vil bli slettet hvis de forhindrer fjerning
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="131"/> <location filename="../src/gui/creds/oauth.cpp" line="131"/>
<source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source> <source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source>
<translation type="unfinished"/> <translation>&lt;h1&gt;Feil bruker&lt;/h1&gt;&lt;p&gt;Du logget inn med bruker &lt;em&gt;%1&lt;/em&gt;, men må logge inn med bruker &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Logg ut av %3 i en annen tab, &lt;a href=&apos;%4&apos;&gt;klikk deretter her&lt;/a&gt; og logg inn som bruker %2&lt;/p&gt;</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@@ -83,7 +83,7 @@
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source> <source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/> <translation>Onbekende fout: antwoord van het netwerk is verwijderd</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
@@ -243,7 +243,7 @@
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="656"/> <location filename="../src/gui/accountsettings.cpp" line="656"/>
<source>Server %1 is currently in maintenance mode.</source> <source>Server %1 is currently in maintenance mode.</source>
<translation type="unfinished"/> <translation>Server %1 is momenteel in onderhoudsmodus.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="658"/> <location filename="../src/gui/accountsettings.cpp" line="658"/>
@@ -253,7 +253,7 @@
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="667"/> <location filename="../src/gui/accountsettings.cpp" line="667"/>
<source>Obtaining authorization from the browser. &lt;a href=&apos;%1&apos;&gt;Click here&lt;/a&gt; to re-open the browser.</source> <source>Obtaining authorization from the browser. &lt;a href=&apos;%1&apos;&gt;Click here&lt;/a&gt; to re-open the browser.</source>
<translation type="unfinished"/> <translation>Probeert autorisatie te krijgen van de browser. 1 Klik hier 1 om de browser opnieuw te openen.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="671"/> <location filename="../src/gui/accountsettings.cpp" line="671"/>
@@ -990,7 +990,7 @@ Doorgaan met deze synchronisatie overschrijft al uw bestanden door een eerdere v
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="209"/> <location filename="../src/gui/folderstatusmodel.cpp" line="209"/>
<source>There are unresolved conflicts. Click for details.</source> <source>There are unresolved conflicts. Click for details.</source>
<translation type="unfinished"/> <translation>Er zijn onopgeloste conflicten. Klik voor details.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="878"/> <location filename="../src/gui/folderstatusmodel.cpp" line="878"/>
@@ -1000,7 +1000,7 @@ Doorgaan met deze synchronisatie overschrijft al uw bestanden door een eerdere v
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="884"/> <location filename="../src/gui/folderstatusmodel.cpp" line="884"/>
<source>Reconciling changes</source> <source>Reconciling changes</source>
<translation type="unfinished"/> <translation>Wijzigingen doorvoeren</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/> <location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
@@ -1434,12 +1434,12 @@ Onderdelen die gewist mogen worden worden verwijderd als ze voorkomen dat een ma
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="133"/> <location filename="../src/gui/issueswidget.ui" line="133"/>
<source>There were too many issues. Not all will be visible here.</source> <source>There were too many issues. Not all will be visible here.</source>
<translation type="unfinished"/> <translation>Er zijn teveel problemen. Niet alles zal worden vertoond.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="155"/> <location filename="../src/gui/issueswidget.ui" line="155"/>
<source>Copy the issues list to the clipboard.</source> <source>Copy the issues list to the clipboard.</source>
<translation type="unfinished"/> <translation>Kopieer de probleemlijst naar het klembord.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="158"/> <location filename="../src/gui/issueswidget.ui" line="158"/>
@@ -1482,7 +1482,7 @@ Onderdelen die gewist mogen worden worden verwijderd als ze voorkomen dat een ma
<message> <message>
<location filename="../src/gui/logbrowser.cpp" line="89"/> <location filename="../src/gui/logbrowser.cpp" line="89"/>
<source>&amp;Capture debug messages</source> <source>&amp;Capture debug messages</source>
<translation type="unfinished"/> <translation>&amp;Capture berichten debuggen</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/logbrowser.cpp" line="101"/> <location filename="../src/gui/logbrowser.cpp" line="101"/>
@@ -1704,17 +1704,17 @@ Onderdelen die gewist mogen worden worden verwijderd als ze voorkomen dat een ma
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="115"/> <location filename="../src/gui/creds/oauth.cpp" line="115"/>
<source>There was an error accessing the &apos;token&apos; endpoint: &lt;br&gt;&lt;em&gt;%1&lt;/em&gt;</source> <source>There was an error accessing the &apos;token&apos; endpoint: &lt;br&gt;&lt;em&gt;%1&lt;/em&gt;</source>
<translation type="unfinished"/> <translation>Er heeft zich een fout voorgedaan bij het verkrijgen van de &apos;token&apos; eindpunt: 1 2 %1 2</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="118"/> <location filename="../src/gui/creds/oauth.cpp" line="118"/>
<source>Could not parse the JSON returned from the server: &lt;br&gt;&lt;em&gt;%1&lt;/em&gt;</source> <source>Could not parse the JSON returned from the server: &lt;br&gt;&lt;em&gt;%1&lt;/em&gt;</source>
<translation type="unfinished"/> <translation>Kon de JSON dat teruggekomen is van de server niet ontleden: 1 2 %1 2</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="121"/> <location filename="../src/gui/creds/oauth.cpp" line="121"/>
<source>The reply from the server did not contain all expected fields</source> <source>The reply from the server did not contain all expected fields</source>
<translation type="unfinished"/> <translation>Het antwoord van de server bevat niet alle verwachte velden</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="125"/> <location filename="../src/gui/creds/oauth.cpp" line="125"/>
@@ -1724,7 +1724,7 @@ Onderdelen die gewist mogen worden worden verwijderd als ze voorkomen dat een ma
<message> <message>
<location filename="../src/gui/creds/oauth.cpp" line="131"/> <location filename="../src/gui/creds/oauth.cpp" line="131"/>
<source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source> <source>&lt;h1&gt;Wrong user&lt;/h1&gt;&lt;p&gt;You logged-in with user &lt;em&gt;%1&lt;/em&gt;, but must login with user &lt;em&gt;%2&lt;/em&gt;.&lt;br&gt;Please log out of %3 in another tab, then &lt;a href=&apos;%4&apos;&gt;click here&lt;/a&gt; and log in as user %2&lt;/p&gt;</source>
<translation type="unfinished"/> <translation>1 Verkeerde gebruiker 1 2 U bent ingelogd met user 3 %1 3, maar dient ingelogd te zijn met user 4 %2 4. 5 Log %3 alstublieft uit in een andere tabblad, vervolgens 6 klikt u hier 6 en log-in als user %2 2</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -1892,7 +1892,7 @@ vragen om extra autorisaties tijdens installatie.</translation>
<message> <message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/> <location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/>
<source>Login in your browser</source> <source>Login in your browser</source>
<translation type="unfinished"/> <translation>Login in uw browser</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -1970,7 +1970,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/>
<source>The server reported the following error:</source> <source>The server reported the following error:</source>
<translation type="unfinished"/> <translation>De server rapporteerde de volgende fout:</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/>
@@ -2132,7 +2132,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/libsync/propagatedownload.cpp" line="459"/> <location filename="../src/libsync/propagatedownload.cpp" line="459"/>
<source>The download would reduce free local disk space below the limit</source> <source>The download would reduce free local disk space below the limit</source>
<translation type="unfinished"/> <translation>De download zal de vrije lokale schijfruimte reduceren tot onder het limiet</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/propagatedownload.cpp" line="463"/> <location filename="../src/libsync/propagatedownload.cpp" line="463"/>
@@ -2319,7 +2319,7 @@ We adviseren deze site niet te gebruiken.</translation>
<location filename="../src/libsync/propagateupload.cpp" line="186"/> <location filename="../src/libsync/propagateupload.cpp" line="186"/>
<location filename="../src/libsync/propagateupload.cpp" line="549"/> <location filename="../src/libsync/propagateupload.cpp" line="549"/>
<source>Upload of %1 exceeds the quota for the folder</source> <source>Upload of %1 exceeds the quota for the folder</source>
<translation type="unfinished"/> <translation>Upload van %1 overtreft de quota van de folder</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/propagateupload.cpp" line="622"/> <location filename="../src/libsync/propagateupload.cpp" line="622"/>
@@ -2659,12 +2659,12 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="35"/> <location filename="../src/gui/sharelinkwidget.ui" line="35"/>
<source>Enter a name to create a new public link...</source> <source>Enter a name to create a new public link...</source>
<translation type="unfinished"/> <translation>Voer een naam in om een nieuwe publieke link aan te maken</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="42"/> <location filename="../src/gui/sharelinkwidget.ui" line="42"/>
<source>&amp;Create new</source> <source>&amp;Create new</source>
<translation type="unfinished"/> <translation>&amp;Create nieuw</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="105"/> <location filename="../src/gui/sharelinkwidget.ui" line="105"/>
@@ -2715,12 +2715,12 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="93"/> <location filename="../src/gui/sharelinkwidget.cpp" line="93"/>
<source>Link shares have been disabled</source> <source>Link shares have been disabled</source>
<translation type="unfinished"/> <translation>Link delen zijn uitgeschakeld</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="107"/> <location filename="../src/gui/sharelinkwidget.cpp" line="107"/>
<source>Create public link share</source> <source>Create public link share</source>
<translation type="unfinished"/> <translation>Maak een verdeelbare publieke link aan</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="168"/> <location filename="../src/gui/sharelinkwidget.cpp" line="168"/>
@@ -2741,7 +2741,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="165"/> <location filename="../src/gui/sharelinkwidget.cpp" line="165"/>
<source>Copy link to clipboard (direct download)</source> <source>Copy link to clipboard (direct download)</source>
<translation type="unfinished"/> <translation>Kopieer de link naar het klembord (directe download)</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="166"/> <location filename="../src/gui/sharelinkwidget.cpp" line="166"/>
@@ -2751,17 +2751,17 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="167"/> <location filename="../src/gui/sharelinkwidget.cpp" line="167"/>
<source>Send link by email (direct download)</source> <source>Send link by email (direct download)</source>
<translation type="unfinished"/> <translation>Verzend link met email (directe download)</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="519"/> <location filename="../src/gui/sharelinkwidget.cpp" line="519"/>
<source>Confirm Link Share Deletion</source> <source>Confirm Link Share Deletion</source>
<translation type="unfinished"/> <translation>Bevestig Gedeelde Link Verwijdering</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="520"/> <location filename="../src/gui/sharelinkwidget.cpp" line="520"/>
<source>&lt;p&gt;Do you really want to delete the public link share &lt;i&gt;%1&lt;/i&gt;?&lt;/p&gt;&lt;p&gt;Note: This action cannot be undone.&lt;/p&gt;</source> <source>&lt;p&gt;Do you really want to delete the public link share &lt;i&gt;%1&lt;/i&gt;?&lt;/p&gt;&lt;p&gt;Note: This action cannot be undone.&lt;/p&gt;</source>
<translation type="unfinished"/> <translation>1 Wilt u echt de verdeelbare publieke link verwijderen 2 %1 2 ? 1 3 Let op: deze actie kan niet ongedaan gemaakt worden. 3</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="527"/> <location filename="../src/gui/sharelinkwidget.cpp" line="527"/>
@@ -2777,7 +2777,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="253"/> <location filename="../src/gui/sharelinkwidget.cpp" line="253"/>
<source>Delete link share</source> <source>Delete link share</source>
<translation type="unfinished"/> <translation>Verwijder verdeelbare link</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="458"/> <location filename="../src/gui/sharelinkwidget.cpp" line="458"/>
@@ -4186,7 +4186,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="33"/> <location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source> <source>Could not open browser</source>
<translation type="unfinished"/> <translation>Kon het browser niet openen</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/guiutility.cpp" line="34"/> <location filename="../src/gui/guiutility.cpp" line="34"/>

View File

@@ -1966,7 +1966,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/>
<source>The server reported the following error:</source> <source>The server reported the following error:</source>
<translation type="unfinished"/> <translation>O servidor retornou o seguinte erro:</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/> <location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/>
@@ -2727,7 +2727,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="163"/> <location filename="../src/gui/sharelinkwidget.cpp" line="163"/>
<source>Open link in browser</source> <source>Open link in browser</source>
<translation type="unfinished"/> <translation>Abrir ligação no navegador</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="164"/> <location filename="../src/gui/sharelinkwidget.cpp" line="164"/>
@@ -2742,7 +2742,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="166"/> <location filename="../src/gui/sharelinkwidget.cpp" line="166"/>
<source>Send link by email</source> <source>Send link by email</source>
<translation>Enviar hiperligação por e-mail</translation> <translation>Enviar hiperligação por correio eletrónico</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.cpp" line="167"/> <location filename="../src/gui/sharelinkwidget.cpp" line="167"/>
@@ -2811,7 +2811,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="235"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="235"/>
<source>Open link in browser</source> <source>Open link in browser</source>
<translation type="unfinished"/> <translation>Abrir ligação no navegador</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="237"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="237"/>
@@ -2821,7 +2821,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="239"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="239"/>
<source>Send link by email</source> <source>Send link by email</source>
<translation>Enviar hiperligação por e-mail</translation> <translation>Enviar hiperligação por correio eletrónico</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="249"/> <location filename="../src/gui/shareusergroupwidget.cpp" line="249"/>
@@ -2939,7 +2939,7 @@ Não é aconselhada a sua utilização.</translation>
<message> <message>
<location filename="../src/gui/socketapi.cpp" line="568"/> <location filename="../src/gui/socketapi.cpp" line="568"/>
<source>Send private link by email...</source> <source>Send private link by email...</source>
<translation type="unfinished"/> <translation>Enviar hiperligação privada por correio eletrónico...</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@@ -83,12 +83,12 @@
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source> <source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/> <translation>Незнайома помилка: відповідь мережі була видалена</translation>
</message> </message>
<message> <message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/> <location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
<source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source> <source>Server replied &quot;%1 %2&quot; to &quot;%3 %4&quot;</source>
<translation type="unfinished"/> <translation>Сервер відповів &quot;%1 %2&quot; на &quot;%3 %4&quot;</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -228,7 +228,7 @@
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="650"/> <location filename="../src/gui/accountsettings.cpp" line="650"/>
<source>The server version %1 is old and unsupported! Proceed at your own risk.</source> <source>The server version %1 is old and unsupported! Proceed at your own risk.</source>
<translation type="unfinished"/> <translation>Версія на вашому сервері %1 застаріла та вже не підтримується! Продовжуйте на свій ризик та розсуд.</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="652"/> <location filename="../src/gui/accountsettings.cpp" line="652"/>
@@ -258,7 +258,7 @@
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="671"/> <location filename="../src/gui/accountsettings.cpp" line="671"/>
<source>Connecting to %1...</source> <source>Connecting to %1...</source>
<translation type="unfinished"/> <translation>З&apos;єднання з %1...</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/accountsettings.cpp" line="674"/> <location filename="../src/gui/accountsettings.cpp" line="674"/>
@@ -567,7 +567,7 @@
<message> <message>
<location filename="../src/gui/application.cpp" line="168"/> <location filename="../src/gui/application.cpp" line="168"/>
<source>Quit ownCloud</source> <source>Quit ownCloud</source>
<translation type="unfinished"/> <translation>Вийти з ownCloud</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -1387,7 +1387,7 @@ Items where deletion is allowed will be deleted if they prevent a directory from
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="20"/> <location filename="../src/gui/issueswidget.ui" line="20"/>
<source>List of issues</source> <source>List of issues</source>
<translation type="unfinished"/> <translation>Перелік проблем</translation>
</message> </message>
<message> <message>
<location filename="../src/gui/issueswidget.ui" line="34"/> <location filename="../src/gui/issueswidget.ui" line="34"/>

View File

@@ -2671,7 +2671,7 @@ It is not advisable to use it.</source>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="220"/> <location filename="../src/gui/sharelinkwidget.ui" line="220"/>
<source>Show file listing</source> <source>Show file listing</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/gui/sharelinkwidget.ui" line="200"/> <location filename="../src/gui/sharelinkwidget.ui" line="200"/>