1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-03 09:11:33 +02:00

Compare commits

..

72 Commits

Author SHA1 Message Date
Markus Goetz
d6e9755121 2.4.2 final 2018-07-18 12:59:25 +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 994 additions and 413 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
=========
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)
* 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)

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 )
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
[![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

View File

@@ -1,6 +1,6 @@
set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 4 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_VERSION_PATCH 2 )
set( MIRALL_VERSION_YEAR 2018 )
set( MIRALL_SOVERSION 0 )

View File

@@ -11,6 +11,7 @@ else()
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0")
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(macosx.pkgproj ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)
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
# 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_tar="$installer.pkg.tar"
installer_file_tar_bz2="$installer.pkg.tar.bz2"

View File

@@ -22,6 +22,7 @@ import subprocess
import commands
import sys
from glob import glob
from distutils.version import LooseVersion
def QueryQMake(attrib):
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')
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_frameworks = []
@@ -334,9 +337,19 @@ def FindQtPlugin(name):
for binary in binaries:
FixBinary(binary)
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
QT_PLUGINS.append('styles/libqmacstyle.dylib')
for plugin in QT_PLUGINS:
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:
print 'Will run %d commands:' % len(commands)
for command in commands:

View File

@@ -27,11 +27,9 @@
<key>CFBundleShortVersionString</key>
<string>@MIRALL_VERSION_STRING@</string>
<key>NSHumanReadableCopyright</key>
<string>(C) 2014-2016 @APPLICATION_VENDOR@</string>
<string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
<key>SUShowReleaseNotes</key>
<false/>
<key>LSMinimumBundleVersion</key>
<string>10.7.0</string>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
</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
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
GenericName[oc]=Dorsièr de Sincronizacion
@@ -362,6 +446,10 @@ Comment[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
GenericName[ko]=폴더 동기화
Name[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
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
GenericName[hu_HU]=Könyvtár szinkronizálás
Name[hu_HU]=@APPLICATION_NAME@ asztali szinkr. kliens

View File

@@ -34,12 +34,15 @@ from gi.repository import GObject, Nautilus
appname = 'ownCloud'
print("Initializing "+appname+"-client-nautilus extension")
print("Using python version {}".format(sys.version_info))
def get_local_path(url):
if url[0:7] == 'file://':
url = url[7:]
unquote = urllib.parse.unquote if python3 else urllib.unquote
return unquote(url)
if python3:
return urllib.parse.unquote(url)
else:
return urllib.unquote(url).decode('utf-8')
def get_runtime_dir():
"""Returns the value of $XDG_RUNTIME_DIR, a directory path.
@@ -61,7 +64,7 @@ class SocketConnect(GObject.GObject):
self._watch_id = 0
self._sock = None
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
# all over the other objects.
@@ -79,7 +82,7 @@ class SocketConnect(GObject.GObject):
# print("Server command: " + cmd)
if self.connected:
try:
self._sock.send(cmd.encode())
self._sock.send(cmd.encode('utf-8'))
except:
print("Sending failed.")
self.reconnect()
@@ -94,18 +97,15 @@ class SocketConnect(GObject.GObject):
self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock_file = os.path.join(get_runtime_dir(), appname, "socket")
try:
print("Socket File: " + sock_file)
self._sock.connect(sock_file) # fails if sock_file doesn't exist
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)
print("Socket watch id: " + str(self._watch_id))
self.sendCommand('GET_STRINGS:\n')
return False # Don't run again
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
print("Connect could not be established, try again later.")
self._sock.close()
@@ -118,24 +118,24 @@ class SocketConnect(GObject.GObject):
# Prepend the remaining data from last call
if len(self._remainder) > 0:
data = self._remainder + data
self._remainder = ''.encode()
self._remainder = ''.encode('utf-8')
if len(data) > 0:
# 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):
self._remainder = data[lastNL+1:]
data = data[:lastNL]
for l in data.split('\n'.encode()):
self._handle_server_response(l.decode())
for l in data.split('\n'.encode('utf-8')):
self._handle_server_response(l.decode('utf-8'))
else:
return False
return True # Run again
def _handle_server_response(self, line):
print("Server response: " + line)
# print("Server response: " + line)
parts = line.split(':')
action = parts[0]
args = parts[1:]
@@ -262,11 +262,11 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
def context_menu_action(self, menu, action, file):
filename = get_local_path(file.get_uri())
print("Context menu: " + action + ' ' + filename)
# print("Context menu: " + action + ' ' + filename)
socketConnect.sendCommand(action + ":" + filename + "\n")
class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
class SyncStateExtension(GObject.GObject, Nautilus.InfoProvider):
def __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)
{
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN)
// See #2693: Some exFAT file systems seem unable to cope with the
// WAL journaling mode. They work fine with DELETE.
QString fileSystem = FileSystem::fileSystemForPath(dbPath);
@@ -74,6 +74,11 @@ static QString defaultJournalMode(const QString &dbPath)
qCInfo(lcDb) << "Filesystem contains FAT - using DELETE journal mode";
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
Q_UNUSED(dbPath)
#endif
@@ -271,6 +276,11 @@ bool SyncJournalDb::sqlFail(const QString &log, const SqlQuery &query)
bool SyncJournalDb::checkConnect()
{
if (_db.isOpen()) {
if (!QFile::exists(_dbFile)) {
qCWarning(lcDb) << "Database open, but file file" + _dbFile + " does not exist";
close();
return false;
}
return true;
}

View File

@@ -1,13 +1,6 @@
PROJECT( CrashReporter )
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
# if(BUILD_RELEASE)
# set(CRASHREPORTER_RELEASE_CHANNEL "release")
@@ -15,9 +8,30 @@ qt_add_resources( crashreporter_RC_RCC ${crashreporter_RC} )
set(CRASHREPORTER_RELEASE_CHANNEL "nightly")
# 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
${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}
"../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) */
if (our_tree->findFile(basePath)) {
other = nullptr;
qCDebug(lcReconcile, "Origin found in our tree : %s", basePath.constData());
qCInfo(lcReconcile, "Origin found in our tree : %s", basePath.constData());
} else {
/* 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
@@ -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.
*/
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");
}
@@ -175,7 +175,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// Some other EVAL_RENAME already claimed other.
// We do nothing: maybe a different candidate for
// 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());
} else if (cur->type == CSYNC_FTW_TYPE_DIR
// 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_UPDATE_METADATA
|| 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->instruction = CSYNC_INSTRUCTION_RENAME;
other->rename_path = cur->path;
if( !cur->file_id.isEmpty() ) {
other->file_id = cur->file_id;
}
if (ctx->current == LOCAL_REPLICA) {
// Keep the local mtime.
other->modtime = cur->modtime;
}
other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE;
// 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.
// Remote: The local replica has already dealt with this.
// 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);
cur->instruction = CSYNC_INSTRUCTION_NONE;
} 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
// due to a remote move of the same file. In these scenarios we just
// want the instruction to stay NEW.
qCDebug(lcReconcile, "Other already has instruction %d",
qCInfo(lcReconcile, "Other already has instruction %d",
other->instruction);
}
};
@@ -223,7 +227,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
if (ctx->current == LOCAL_REPLICA) {
/* use the old name to find the "other" node */
OCC::SyncJournalFileRecord base;
qCDebug(lcReconcile, "Finding rename origin through inode %" PRIu64 "",
qCInfo(lcReconcile, "Finding rename origin through inode %" PRIu64 "",
cur->inode);
ctx->statedb->getFileRecordByInode(cur->inode, &base);
renameCandidateProcessing(base._path);
@@ -236,7 +240,7 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
// line.
auto basePath = csync_rename_adjust_full_path_source(ctx, 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());
// We go through getFileRecordsByFileId to ensure the basePath
// 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
if (!processedRename) {
qCDebug(lcReconcile, "Finding rename origin through file ID %s",
qCInfo(lcReconcile, "Finding rename origin through file ID %s",
cur->file_id.constData());
ctx->statedb->getFileRecordsByFileId(cur->file_id,
[&](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.
* Keep it here for now */
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;
}
} else {
/* 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) {
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);
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());
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->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! */
qCInfo(lcUpdate, "Database entry found, compare: %" 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),
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) {
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;
}
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;
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
* 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;
}
/* 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) {
/* 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;
} else {
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 {
/* check if it's a file and has been renamed */
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;
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,
ctx->callbacks.checksum_userdata);
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;
}
}
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 */
fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
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;
} else {
qCInfo(lcUpdate, "Checking for rename based on fileid %s", fs->file_id.constData());
/* Remote Replica Rename check */
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);
}
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;
done = true;
};
@@ -458,11 +462,11 @@ int csync_walker(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
}
break;
case CSYNC_FTW_TYPE_SLINK:
qCDebug(lcUpdate, "symlink: %s - not supported", fs->path.constData());
qCInfo(lcUpdate, "symlink: %s - not supported", fs->path.constData());
break;
default:
qCInfo(lcUpdate, "item: %s - item type %d not iterated", fs->path.constData(), fs->type);
return 0;
break;
}
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.
*/
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 += '/';
return;
@@ -720,7 +724,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
}
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;

View File

@@ -136,7 +136,7 @@ IF( APPLE )
if(SPARKLE_FOUND)
# Define this, we need to check in updater.cpp
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()

View File

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

View File

@@ -121,6 +121,10 @@ void Folder::checkLocalPath()
{
const QFileInfo fi(_definition.localPath);
_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()) {
qCWarning(lcFolder) << "Broken symlink:" << _definition.localPath;
_canonicalLocalPath = _definition.localPath;

View File

@@ -25,6 +25,10 @@
#include "updater/updater.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 "config.h"
@@ -32,6 +36,7 @@
#include <QNetworkProxy>
#include <QDir>
#include <QScopedValueRollback>
#include <QMessageBox>
namespace OCC {
@@ -88,6 +93,18 @@ GeneralSettings::GeneralSettings(QWidget *parent)
// accountAdded means the wizard was finished and the wizard might change some options.
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()
@@ -117,22 +134,79 @@ void GeneralSettings::loadMiscSettings()
void GeneralSettings::slotUpdateInfo()
{
// Note: the sparkle-updater is not an OCUpdater
OCUpdater *updater = qobject_cast<OCUpdater *>(Updater::instance());
if (ConfigFile().skipUpdateCheck()) {
updater = 0; // don't show update info if updates are disabled
if (ConfigFile().skipUpdateCheck() || !Updater::instance()) {
// updater disabled on compile
_ui->updatesGroupBox->setVisible(false);
return;
}
if (updater) {
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
// Note: the sparkle-updater is not an OCUpdater
OCUpdater *ocupdater = qobject_cast<OCUpdater *>(Updater::instance());
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);
_ui->updateStateLabel->setText(updater->statusString());
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
} else {
// can't have those infos from sparkle currently
_ui->updatesGroupBox->setVisible(false);
_ui->updateStateLabel->setText(ocupdater->statusString());
_ui->restartButton->setVisible(ocupdater->downloadState() == OCUpdater::DownloadComplete);
}
#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()

View File

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

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>785</width>
<height>523</height>
<height>533</height>
</rect>
</property>
<property name="windowTitle">
@@ -74,48 +74,88 @@
<property name="title">
<string>Updates</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="updateStateLabel">
<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>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="updateChannelLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Channel</string>
</property>
<property name="buddy">
<cstring>updateChannel</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="updateChannel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>stable</string>
</property>
</item>
<item>
<property name="text">
<string>beta</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="updateStateLabel">
<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>
</layout>
</widget>
@@ -247,7 +287,10 @@
<tabstop>ignoredFilesButton</tabstop>
<tabstop>newFolderLimitCheckBox</tabstop>
<tabstop>newFolderLimitSpinBox</tabstop>
<tabstop>newExternalStorage</tabstop>
<tabstop>showInExplorerNavigationPaneCheckBox</tabstop>
<tabstop>crashreporterCheckBox</tabstop>
<tabstop>updateChannel</tabstop>
<tabstop>restartButton</tabstop>
</tabstops>
<resources/>

View File

@@ -50,18 +50,13 @@ const char propertyAccountC[] = "oc_account";
ownCloudGui::ownCloudGui(Application *parent)
: QObject(parent)
, _tray(0)
,
#if defined(Q_OS_MAC)
_settingsDialog(new SettingsDialogMac(this))
,
, _settingsDialog(new SettingsDialogMac(this))
#else
_settingsDialog(new SettingsDialog(this))
,
, _settingsDialog(new SettingsDialog(this))
#endif
_logBrowser(0)
, _contextMenuVisibleOsx(false)
, _logBrowser(0)
, _recentActionsMenu(0)
, _qdbusmenuWorkaround(false)
, _app(parent)
{
_tray = new Systray();
@@ -117,7 +112,7 @@ void ownCloudGui::slotOpenSettingsDialog()
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
{
if (_qdbusmenuWorkaround) {
if (_workaroundFakeDoubleClick) {
static QElapsedTimer last_click;
if (last_click.isValid() && last_click.elapsed() < 200) {
return;
@@ -381,17 +376,19 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
void ownCloudGui::slotContextMenuAboutToShow()
{
// For some reason on OS X _contextMenu->isVisible returns always false
_contextMenuVisibleOsx = true;
_contextMenuVisibleManual = true;
// Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus();
if (!_workaroundNoAboutToShowUpdate) {
updateContextMenu();
}
}
void ownCloudGui::slotContextMenuAboutToHide()
{
// For some reason on OS X _contextMenu->isVisible returns always false
_contextMenuVisibleOsx = false;
_contextMenuVisibleManual = false;
// Update icon in sys tray, as it might change depending on the context menu state
slotComputeOverallSyncStatus();
@@ -399,11 +396,11 @@ void ownCloudGui::slotContextMenuAboutToHide()
bool ownCloudGui::contextMenuVisible() const
{
#ifdef Q_OS_MAC
return _contextMenuVisibleOsx;
#else
// On some platforms isVisible doesn't work and always returns false,
// elsewhere aboutToHide is unreliable.
if (_workaroundManualVisibility)
return _contextMenuVisibleManual;
return _contextMenu->isVisible();
#endif
}
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");
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()
{
if (_contextMenu) {
@@ -454,51 +475,65 @@ void ownCloudGui::setupContextMenu()
return;
}
// Enables workarounds for bugs introduced in Qt 5.5.0
// In particular QTBUG-47863 #3672 (tray menu fails to update and
// becomes unresponsive) and QTBUG-48068 #3722 (click signal is
// emitted several times)
// The Qt version check intentionally uses 5.0.0 (where platformMenu()
// 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
auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
if (value == "1")
*sw = true;
if (value == "0")
*sw = false;
};
if (forceQDBusTrayWorkaround() == "1") {
_qdbusmenuWorkaround = true;
} else if (forceQDBusTrayWorkaround() == "0") {
_qdbusmenuWorkaround = false;
// This is an old compound flag that people might still depend on
bool qdbusmenuWorkarounds = false;
applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
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
// https://bugreports.qt.io/browse/QTBUG-54633
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
#else
connect(_contextMenu.data(), &QMenu::aboutToShow, this, &ownCloudGui::updateContextMenu);
// https://bugreports.qt.io/browse/QTBUG-54633
_workaroundNoAboutToShowUpdate = true;
_workaroundManualVisibility = true;
#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.
updateContextMenu();
@@ -510,13 +545,21 @@ void ownCloudGui::updateContextMenu()
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)
// we need to hide and show the tray icon. We don't want to do that
// while it's visible!
if (contextMenuVisible()) {
if (!_workaroundBatchTrayUpdate.isActive()) {
_workaroundBatchTrayUpdate.start();
if (!_delayedTrayUpdateTimer.isActive()) {
_delayedTrayUpdateTimer.start();
}
return;
}
@@ -631,35 +674,30 @@ void ownCloudGui::updateContextMenu()
}
_contextMenu->addAction(_actionQuit);
if (_qdbusmenuWorkaround) {
if (_workaroundShowAndHideTray) {
_tray->show();
}
}
void ownCloudGui::updateContextMenuNeeded()
{
// For the workaround case updating while visible is impossible. Instead
// occasionally update the menu when it's invisible.
if (_qdbusmenuWorkaround) {
if (!_workaroundBatchTrayUpdate.isActive()) {
_workaroundBatchTrayUpdate.start();
}
// if it's visible and we can update live: update now
if (contextMenuVisible() && updateWhileVisible()) {
// Note: don't update while visible on OSX
// https://bugreports.qt.io/browse/QTBUG-54845
updateContextMenu();
return;
}
#ifdef Q_OS_MAC
// https://bugreports.qt.io/browse/QTBUG-54845
// We cannot update on demand or while visible -> update when invisible.
if (!contextMenuVisible()) {
updateContextMenu();
// if we can't lazily update: update later
if (_workaroundNoAboutToShowUpdate) {
// Note: don't update immediately even in the invisible case
// as that can lead to extremely frequent menu updates
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)

View File

@@ -119,14 +119,19 @@ private:
// tray's menu
QScopedPointer<QMenu> _contextMenu;
// Manually tracking whether the context menu is visible, but only works
// on OSX because aboutToHide is not reliable everywhere.
bool _contextMenuVisibleOsx;
// Manually tracking whether the context menu is visible via aboutToShow
// and aboutToHide. Unfortunately aboutToHide isn't reliable everywhere
// so this only gets used with _workaroundManualVisibility (when the tray's
// isVisible() is unreliable)
bool _contextMenuVisibleManual = false;
QMenu *_recentActionsMenu;
QVector<QMenu *> _accountMenus;
bool _qdbusmenuWorkaround;
QTimer _workaroundBatchTrayUpdate;
bool _workaroundShowAndHideTray = false;
bool _workaroundNoAboutToShowUpdate = false;
bool _workaroundFakeDoubleClick = false;
bool _workaroundManualVisibility = false;
QTimer _delayedTrayUpdateTimer;
QMap<QString, QPointer<ShareDialog>> _shareDialogs;
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 official signed packages: "9B5WD74GWJ." "com.owncloud.desktopclient" ".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()) {
QString runtimeDir;
runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
@@ -220,6 +224,11 @@ SocketApi::~SocketApi()
// All remaining sockets will be destroyed with _localServer, their parent
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
_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()

View File

@@ -204,6 +204,10 @@ void SslButton::slotUpdateMenu()
AccountPtr account = _accountState->account();
if (account->isHttp2Supported()) {
_menu->addAction("HTTP/2")->setEnabled(false);
}
if (account->url().scheme() == QLatin1String("https")) {
QString sslVersion = account->_sessionCipher.protocolString()
+ ", " + 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()
{
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()
{
ConfigFile cfg;
@@ -187,8 +267,30 @@ void OCUpdater::slotStartInstaller()
settings.setValue(autoUpdateAttemptedC, true);
settings.sync();
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()
@@ -298,7 +400,7 @@ void NSISUpdater::versionInfoArrived(const UpdateInfo &info)
showDialog(info);
}
if (!url.isEmpty()) {
_targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/'));
_targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')+1);
if (QFile(_targetFile).exists()) {
setDownloadState(DownloadComplete);
} else {

View File

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

View File

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

View File

@@ -73,7 +73,7 @@ class SparkleUpdater::Private
};
// Delete ~/Library//Preferences/com.owncloud.desktopclient.plist to re-test
SparkleUpdater::SparkleUpdater(const QString& appCastUrl)
SparkleUpdater::SparkleUpdater(const QUrl& appCastUrl)
: Updater()
{
d = new Private;
@@ -89,9 +89,7 @@ SparkleUpdater::SparkleUpdater(const QString& appCastUrl)
[d->updater resetUpdateCycle];
[d->updater retain];
NSURL* url = [NSURL URLWithString:
[NSString stringWithUTF8String: appCastUrl.toUtf8().data()]];
[d->updater setFeedURL: url];
setUpdateUrl(appCastUrl);
// Sparkle 1.8 required
NSString *userAgent = [NSString stringWithUTF8String: Utility::userAgentString().data()];
@@ -104,7 +102,14 @@ SparkleUpdater::~SparkleUpdater()
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()
{
// 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

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,7 @@
#include "theme.h"
#include "common/utility.h"
#include "common/asserts.h"
#include "version.h"
#include "creds/abstractcredentials.h"
@@ -52,6 +53,7 @@ static const char crashReporterC[] = "crashReporter";
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char updateCheckIntervalC[] = "updateCheckInterval";
static const char updateChannelC[] = "updateChannel";
static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout";
static const char chunkSizeC[] = "chunkSize";
@@ -468,6 +470,28 @@ void ConfigFile::setSkipUpdateCheck(bool skip, const QString &connection)
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
{
QSettings settings(configFile(), QSettings::IniFormat);

View File

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

View File

@@ -117,6 +117,7 @@ HttpCredentials::HttpCredentials(const QString &user, const QString &password, c
, _clientSslKey(key)
, _clientSslCertificate(certificate)
, _keychainMigration(false)
, _retryOnKeyChainError(false)
{
}
@@ -219,6 +220,21 @@ void HttpCredentials::deleteOldKeychainEntries()
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
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {

View File

@@ -141,6 +141,7 @@ protected:
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
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;
qCWarning(lcPropagator) << "No valid fileinfo";
} else {
// Need to normalize to composited form because of
// https://bugreports.qt-project.org/browse/QTBUG-39622
// Need to normalize to composited form because of QTBUG-39622/QTBUG-55896
const QString cName = fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_C);
bool equal = (file == cName);
re = (!equal && !cName.endsWith(relFile, Qt::CaseSensitive));
@@ -821,10 +820,13 @@ void PropagatorCompositeJob::slotSubJobFinished(SyncFileItem::Status status)
ASSERT(i >= 0);
_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
|| status == SyncFileItem::NormalError
|| status == SyncFileItem::SoftError
|| status == SyncFileItem::DetailError) {
|| status == SyncFileItem::DetailError
|| status == SyncFileItem::BlacklistedError) {
_hasError = status;
}

View File

@@ -553,6 +553,16 @@ void PropagateUploadFileCommon::commonErrorHandling(AbstractNetworkJob *job)
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)
{
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job), _jobs.end());

View File

@@ -281,6 +281,17 @@ protected:
*/
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
QMap<QByteArray, QByteArray> headers();
};

View File

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

View File

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

View File

@@ -82,10 +82,9 @@ public:
/** For files whose errors were blacklisted
*
* 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
* should not cause the sync run to fail.
* errors should appear in the issues tab but should be silent otherwise.
*
* A DetailError that doesn't cause sync failure.
* A SoftError caused by blacklisting.
*/
BlacklistedError
};

View File

@@ -576,6 +576,51 @@ private slots:
//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)

View File

@@ -373,7 +373,7 @@
<message>
<location filename="../src/gui/accountstate.cpp" line="132"/>
<source>Maintenance mode</source>
<translation type="unfinished"/>
<translation>Mode de manteniment</translation>
</message>
<message>
<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>
<location filename="../src/gui/issueswidget.ui" line="73"/>
<source>Show warnings</source>
<translation type="unfinished"/>
<translation>Mostra avisos</translation>
</message>
<message>
<location filename="../src/gui/issueswidget.ui" line="83"/>
<source>Show ignored files</source>
<translation type="unfinished"/>
<translation>Mostra arxius descartats</translation>
</message>
<message>
<location filename="../src/gui/issueswidget.ui" line="133"/>
@@ -2507,7 +2507,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/servernotificationhandler.cpp" line="103"/>
<source>Dismiss</source>
<translation type="unfinished"/>
<translation>Ignora</translation>
</message>
</context>
<context>
@@ -2622,12 +2622,12 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/sharedialog.cpp" line="211"/>
<source>Users and Groups</source>
<translation type="unfinished"/>
<translation>Usuaris i Grups</translation>
</message>
<message>
<location filename="../src/gui/sharedialog.cpp" line="218"/>
<source>Public Links</source>
<translation type="unfinished"/>
<translation>Enllaços públics</translation>
</message>
</context>
<context>
@@ -2650,7 +2650,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="35"/>
<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>
<location filename="../src/gui/sharelinkwidget.ui" line="42"/>
@@ -2670,12 +2670,12 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="178"/>
<source>Link properties:</source>
<translation type="unfinished"/>
<translation>Propietats de l&apos;enllaç:</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="220"/>
<source>Show file listing</source>
<translation type="unfinished"/>
<translation>Motra el llistat de fitxers</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="200"/>
@@ -2685,7 +2685,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="20"/>
<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>
<location filename="../src/gui/sharelinkwidget.cpp" line="117"/>
@@ -2727,7 +2727,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="164"/>
<source>Copy link to clipboard</source>
<translation type="unfinished"/>
<translation>Copiar al portadocuments</translation>
</message>
<message>
<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="543"/>
<source>Public link</source>
<translation type="unfinished"/>
<translation>Enllaç públic</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="253"/>
@@ -2811,7 +2811,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="237"/>
<source>Copy link to clipboard</source>
<translation type="unfinished"/>
<translation>Copiar al portadocuments</translation>
</message>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="239"/>
@@ -2826,7 +2826,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="337"/>
<source>I shared something with you</source>
<translation type="unfinished"/>
<translation>He compartit amb tu</translation>
</message>
</context>
<context>
@@ -2919,7 +2919,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/socketapi.cpp" line="557"/>
<source>I shared something with you</source>
<translation type="unfinished"/>
<translation>He compartit amb tu</translation>
</message>
<message>
<location filename="../src/gui/socketapi.cpp" line="565"/>
@@ -3850,7 +3850,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/>
<source>Re-open Browser</source>
<translation type="unfinished"/>
<translation>Reobrir navegador</translation>
</message>
</context>
<context>
@@ -4177,7 +4177,7 @@ No és aconsellada usar-la.</translation>
<message>
<location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source>
<translation type="unfinished"/>
<translation>No es pot obrir el navegador</translation>
</message>
<message>
<location filename="../src/gui/guiutility.cpp" line="34"/>

View File

@@ -83,12 +83,12 @@
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/>
<translation>Neznámá chyba: odpověď sítě byla smazána</translation>
</message>
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
<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>
</context>
<context>
@@ -388,7 +388,7 @@
<message>
<location filename="../src/gui/accountstate.cpp" line="138"/>
<source>Asking Credentials</source>
<translation type="unfinished"/>
<translation>Požádat o pověření</translation>
</message>
<message>
<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>
<location filename="../src/gui/folderstatusmodel.cpp" line="209"/>
<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>
<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>
<location filename="../src/gui/issueswidget.ui" line="20"/>
<source>List of issues</source>
<translation type="unfinished"/>
<translation>Seznam problémů</translation>
</message>
<message>
<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="304"/>
<source>Synchronization is paused</source>
<translation type="unfinished"/>
<translation>Synchronizace je pozastavena</translation>
</message>
<message>
<location filename="../src/gui/owncloudgui.cpp" line="306"/>
<source>Error during synchronization</source>
<translation type="unfinished"/>
<translation>Chyba při synchronizaci</translation>
</message>
<message>
<location filename="../src/gui/owncloudgui.cpp" line="314"/>
@@ -3843,17 +3843,17 @@ Nedoporučuje se jí používat.</translation>
<message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="36"/>
<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>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="46"/>
<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>
<location filename="../src/gui/wizard/owncloudoauthcredspage.ui" line="56"/>
<source>Re-open Browser</source>
<translation type="unfinished"/>
<translation>Znovu otevřít prohlížeč</translation>
</message>
</context>
<context>
@@ -4180,7 +4180,7 @@ Nedoporučuje se jí používat.</translation>
<message>
<location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source>
<translation type="unfinished"/>
<translation>Nemohu otevřít prohlížeč</translation>
</message>
<message>
<location filename="../src/gui/guiutility.cpp" line="34"/>

View File

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

View File

@@ -83,12 +83,12 @@
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
<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>
</context>
<context>
@@ -253,7 +253,7 @@
<message>
<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>
<translation type="unfinished"/>
<translation>&lt;a href=&apos;%1&apos;&gt;&lt;/a&gt; </translation>
</message>
<message>
<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>
<location filename="../src/gui/issueswidget.ui" line="133"/>
<source>There were too many issues. Not all will be visible here.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/gui/issueswidget.ui" line="155"/>
<source>Copy the issues list to the clipboard.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<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>
<location filename="../src/gui/creds/oauth.cpp" line="112"/>
<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>
<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>
<location filename="../src/gui/creds/oauth.cpp" line="121"/>
<source>The reply from the server did not contain all expected fields</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<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>
<translation type="unfinished"/>
<translation>&lt;h1&gt;&lt;/h1&gt;&lt;p&gt;%1&lt;/p&gt; </translation>
</message>
<message>
<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>
<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>
</context>
<context>
@@ -1885,7 +1885,7 @@ for additional privileges during the process.</source>
<message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/>
<source>Login in your browser</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>
@@ -1962,7 +1962,7 @@ It is not advisable to use it.</source>
<message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/>
<source>The server reported the following error:</source>
<translation type="unfinished"/>
<translation>:</translation>
</message>
<message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/>
@@ -2723,12 +2723,12 @@ It is not advisable to use it.</source>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="163"/>
<source>Open link in browser</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="164"/>
<source>Copy link to clipboard</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="165"/>
@@ -2807,12 +2807,12 @@ It is not advisable to use it.</source>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="235"/>
<source>Open link in browser</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="237"/>
<source>Copy link to clipboard</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/gui/shareusergroupwidget.cpp" line="239"/>
@@ -4178,12 +4178,12 @@ It is not advisable to use it.</source>
<message>
<location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<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>
<translation type="unfinished"/>
<translation>URL %1 </translation>
</message>
<message>
<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>
<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>
<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>
</context>
<context>

View File

@@ -83,7 +83,7 @@
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="247"/>
<source>Unknown error: network reply was deleted</source>
<translation type="unfinished"/>
<translation>Onbekende fout: antwoord van het netwerk is verwijderd</translation>
</message>
<message>
<location filename="../src/libsync/abstractnetworkjob.cpp" line="390"/>
@@ -243,7 +243,7 @@
<message>
<location filename="../src/gui/accountsettings.cpp" line="656"/>
<source>Server %1 is currently in maintenance mode.</source>
<translation type="unfinished"/>
<translation>Server %1 is momenteel in onderhoudsmodus.</translation>
</message>
<message>
<location filename="../src/gui/accountsettings.cpp" line="658"/>
@@ -253,7 +253,7 @@
<message>
<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>
<translation type="unfinished"/>
<translation>Probeert autorisatie te krijgen van de browser. 1 Klik hier 1 om de browser opnieuw te openen.</translation>
</message>
<message>
<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>
<location filename="../src/gui/folderstatusmodel.cpp" line="209"/>
<source>There are unresolved conflicts. Click for details.</source>
<translation type="unfinished"/>
<translation>Er zijn onopgeloste conflicten. Klik voor details.</translation>
</message>
<message>
<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>
<location filename="../src/gui/folderstatusmodel.cpp" line="884"/>
<source>Reconciling changes</source>
<translation type="unfinished"/>
<translation>Wijzigingen doorvoeren</translation>
</message>
<message>
<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>
<location filename="../src/gui/issueswidget.ui" line="133"/>
<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>
<location filename="../src/gui/issueswidget.ui" line="155"/>
<source>Copy the issues list to the clipboard.</source>
<translation type="unfinished"/>
<translation>Kopieer de probleemlijst naar het klembord.</translation>
</message>
<message>
<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>
<location filename="../src/gui/logbrowser.cpp" line="89"/>
<source>&amp;Capture debug messages</source>
<translation type="unfinished"/>
<translation>&amp;Capture berichten debuggen</translation>
</message>
<message>
<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>
<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>
<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>
<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>
<translation type="unfinished"/>
<translation>Kon de JSON dat teruggekomen is van de server niet ontleden: 1 2 %1 2</translation>
</message>
<message>
<location filename="../src/gui/creds/oauth.cpp" line="121"/>
<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>
<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>
<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>
<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>
</context>
<context>
@@ -1892,7 +1892,7 @@ vragen om extra autorisaties tijdens installatie.</translation>
<message>
<location filename="../src/gui/wizard/owncloudoauthcredspage.cpp" line="44"/>
<source>Login in your browser</source>
<translation type="unfinished"/>
<translation>Login in uw browser</translation>
</message>
</context>
<context>
@@ -1970,7 +1970,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="297"/>
<source>The server reported the following error:</source>
<translation type="unfinished"/>
<translation>De server rapporteerde de volgende fout:</translation>
</message>
<message>
<location filename="../src/gui/owncloudsetupwizard.cpp" line="452"/>
@@ -2132,7 +2132,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/libsync/propagatedownload.cpp" line="459"/>
<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>
<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="549"/>
<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>
<location filename="../src/libsync/propagateupload.cpp" line="622"/>
@@ -2659,12 +2659,12 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="35"/>
<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>
<location filename="../src/gui/sharelinkwidget.ui" line="42"/>
<source>&amp;Create new</source>
<translation type="unfinished"/>
<translation>&amp;Create nieuw</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.ui" line="105"/>
@@ -2715,12 +2715,12 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="93"/>
<source>Link shares have been disabled</source>
<translation type="unfinished"/>
<translation>Link delen zijn uitgeschakeld</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="107"/>
<source>Create public link share</source>
<translation type="unfinished"/>
<translation>Maak een verdeelbare publieke link aan</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="168"/>
@@ -2741,7 +2741,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="165"/>
<source>Copy link to clipboard (direct download)</source>
<translation type="unfinished"/>
<translation>Kopieer de link naar het klembord (directe download)</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="166"/>
@@ -2751,17 +2751,17 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="167"/>
<source>Send link by email (direct download)</source>
<translation type="unfinished"/>
<translation>Verzend link met email (directe download)</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="519"/>
<source>Confirm Link Share Deletion</source>
<translation type="unfinished"/>
<translation>Bevestig Gedeelde Link Verwijdering</translation>
</message>
<message>
<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>
<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>
<location filename="../src/gui/sharelinkwidget.cpp" line="527"/>
@@ -2777,7 +2777,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="253"/>
<source>Delete link share</source>
<translation type="unfinished"/>
<translation>Verwijder verdeelbare link</translation>
</message>
<message>
<location filename="../src/gui/sharelinkwidget.cpp" line="458"/>
@@ -4186,7 +4186,7 @@ We adviseren deze site niet te gebruiken.</translation>
<message>
<location filename="../src/gui/guiutility.cpp" line="33"/>
<source>Could not open browser</source>
<translation type="unfinished"/>
<translation>Kon het browser niet openen</translation>
</message>
<message>
<location filename="../src/gui/guiutility.cpp" line="34"/>

View File

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

View File

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

View File

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