mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-15 03:44:07 +02:00
Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee71024496 | ||
|
|
b1f326054f | ||
|
|
bceb40ed80 | ||
|
|
fd684eda52 | ||
|
|
9e3c3353bd | ||
|
|
07ffff3d77 | ||
|
|
9b34427a1c | ||
|
|
5fba476076 | ||
|
|
d63abef718 | ||
|
|
cdba8a7f2f | ||
|
|
21967a130b | ||
|
|
08e78d5d6f | ||
|
|
fe68e1e82c | ||
|
|
25ac3bfdb7 | ||
|
|
4700c604b1 | ||
|
|
356fa737c5 | ||
|
|
520e2eb392 | ||
|
|
e0d2bd4830 | ||
|
|
1dc05f99bf | ||
|
|
b2b176bcd0 | ||
|
|
fde5ccd0df | ||
|
|
d1fe25cc31 | ||
|
|
60c18f75b5 | ||
|
|
c7f3791f3d | ||
|
|
ee9d5e6bf0 | ||
|
|
96fa3a3a1a | ||
|
|
7c4deec800 | ||
|
|
78e82eb920 | ||
|
|
3c91a1ace4 | ||
|
|
3a52db46ad | ||
|
|
137bce6dd0 | ||
|
|
f000e6ce6a | ||
|
|
7c1281dd06 | ||
|
|
60729f2bbd | ||
|
|
0b0ecfcbe4 | ||
|
|
1fe86bced2 | ||
|
|
c6a62a497d | ||
|
|
8be6881093 | ||
|
|
99c8118229 | ||
|
|
6c5ca055c4 | ||
|
|
a6ec8f3090 | ||
|
|
b039c2ce86 | ||
|
|
5a6d286c41 | ||
|
|
ba65187ad3 | ||
|
|
a91f54f0a8 | ||
|
|
d77c1f3e4a | ||
|
|
7390ddbd98 | ||
|
|
32a4b40f0a | ||
|
|
bc1bc2a4f8 | ||
|
|
155c965866 | ||
|
|
6c73f25747 | ||
|
|
2518fd7059 | ||
|
|
56edae6958 | ||
|
|
d8275cd4e1 | ||
|
|
c3dca7a288 | ||
|
|
96ff0076c7 | ||
|
|
8bb4af067a | ||
|
|
df0df76b51 | ||
|
|
458f336405 | ||
|
|
3f3f27d4d3 | ||
|
|
7c9cffa5ae | ||
|
|
996223197c | ||
|
|
b8e7555977 | ||
|
|
ed80a712ab | ||
|
|
2866e56c51 | ||
|
|
2074bdbb19 | ||
|
|
d212ac7d16 | ||
|
|
d2bae21b14 | ||
|
|
4283ab3b44 | ||
|
|
c579069071 | ||
|
|
88488c695c | ||
|
|
21594e9aa9 | ||
|
|
9ffacd4ecd | ||
|
|
9d5f5ea3bc | ||
|
|
2dbd27af76 | ||
|
|
0634a4d0c6 | ||
|
|
fa80a006b8 | ||
|
|
9d88ef5432 | ||
|
|
7b99877c68 | ||
|
|
ec81cdefb0 | ||
|
|
454d5b575c | ||
|
|
785b59e6d1 | ||
|
|
9d8fc4aa4d | ||
|
|
57ac1d9ea2 | ||
|
|
d9ea6936ab | ||
|
|
c917251e9e | ||
|
|
c805c5d6e9 | ||
|
|
adcf40afc3 | ||
|
|
d986011067 | ||
|
|
5a83636f81 | ||
|
|
d475628c70 | ||
|
|
4a890eae38 | ||
|
|
760e11bc5d | ||
|
|
96ebf2b519 | ||
|
|
4a6f4919d7 | ||
|
|
b98040c7d5 | ||
|
|
1240a8163d | ||
|
|
e15b9b5358 | ||
|
|
1617c9d482 | ||
|
|
16600fe86a | ||
|
|
50ba73860c | ||
|
|
750cdc1910 | ||
|
|
f4e2c84111 | ||
|
|
4f27750711 | ||
|
|
71d9f23068 | ||
|
|
9f7aed7602 | ||
|
|
7f2213416a | ||
|
|
9b9f0bdd4d | ||
|
|
ee0aec514f | ||
|
|
c2fd7d6ebd | ||
|
|
4a893c5267 | ||
|
|
2473183f19 | ||
|
|
7d7142d7d8 | ||
|
|
cb57cda87a | ||
|
|
f2fa812b0b | ||
|
|
ef89582d7e | ||
|
|
ae74a21305 | ||
|
|
32af63764c | ||
|
|
61ff90409d | ||
|
|
ba0c3256fa | ||
|
|
b6fe5d2cff | ||
|
|
9123fac545 | ||
|
|
c6bc388001 | ||
|
|
ea985a85af | ||
|
|
2578832002 | ||
|
|
cfada67aa6 | ||
|
|
5483682281 | ||
|
|
2a8c23aac3 | ||
|
|
88bc96fc4c | ||
|
|
588129d852 | ||
|
|
0889991c38 | ||
|
|
5c87a35fe4 | ||
|
|
418185af9a | ||
|
|
4b56cc6e08 | ||
|
|
3cef771868 | ||
|
|
59b20de7cd | ||
|
|
e0ae34f01b | ||
|
|
a9a24c96fc | ||
|
|
a202203325 | ||
|
|
83c3d76966 | ||
|
|
99734f8d72 | ||
|
|
570a0bb586 | ||
|
|
450a815d61 | ||
|
|
dafc2d2b73 | ||
|
|
0bd2edd33a | ||
|
|
807267cfdb | ||
|
|
48c9222578 | ||
|
|
b5ea56df73 | ||
|
|
2fdf6dd8f2 | ||
|
|
5b8c9eb16f | ||
|
|
9c05150c12 | ||
|
|
c7eb85ef78 | ||
|
|
4df455f2e0 | ||
|
|
653a00d63d | ||
|
|
3c9acdf724 | ||
|
|
e81d1ab9b8 | ||
|
|
ad5620efb5 | ||
|
|
f455c71338 | ||
|
|
033f2cd231 | ||
|
|
c9eccd729d | ||
|
|
b1100cd9e5 | ||
|
|
8f728ddfb2 | ||
|
|
4ef0ce112c | ||
|
|
57c14a0eba | ||
|
|
89f831e7d4 | ||
|
|
917b8409ae | ||
|
|
86fd39e3a9 | ||
|
|
04db332051 | ||
|
|
06a2f58c51 | ||
|
|
b87d55758b |
48
ChangeLog
48
ChangeLog
@@ -1,6 +1,52 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
version 1.8.0 (release 2015-03-xx)
|
version 1.8.1 (release 2015-05-07)
|
||||||
|
* Make "operation canceled" error a soft error
|
||||||
|
* Do not throw an error for files that are scheduled to be removed,
|
||||||
|
but can not be found on the server. #2919
|
||||||
|
* Windows: Reset QNAM to proper function after hibernation. #2899 #2895 #2973
|
||||||
|
* Fix argument verification of --confdir #2453
|
||||||
|
* Fix a crash when accessing a dangling UploadDevice pointer #2984
|
||||||
|
* Add-folder wizard: Make sure there is a scrollbar if folder names
|
||||||
|
are too long #2962
|
||||||
|
* Add-folder Wizard: Select the newly created folder
|
||||||
|
* Activity: Correctly restore column sizes #3005
|
||||||
|
* SSL Button: do not crash on empty certificate chain
|
||||||
|
* SSL Button: Make menu creation lazy #3007 #2990
|
||||||
|
* Lookup system proxy async to avoid hangs #2993 #2802
|
||||||
|
* ShareDialog: Some GUI refinements
|
||||||
|
* ShareDialog: On creation of a share always retrieve the share
|
||||||
|
This makes sure that if a default expiration date is set this is reflected
|
||||||
|
in the dialog. #2889
|
||||||
|
* ShareDialog: Only show share dialog if we are connected.
|
||||||
|
* HttpCreds: Fill pw dialog with previous password. #2848 #2879
|
||||||
|
* HttpCreds: Delete password from old location. #2186
|
||||||
|
* Do not store Session Cookies in the client cookie storage
|
||||||
|
* CookieJar: Don't accidentally overwrite cookies. #2808
|
||||||
|
* ProtocolWidget: Always add seconds to the DateTime locale. #2535
|
||||||
|
* Updater: Give context as to which app is about to be updated #3040
|
||||||
|
* Windows: Add version information for owncloud.exe. This should help us know
|
||||||
|
what version or build number a crash report was generated with.
|
||||||
|
* Fix a crash on shutdown in ~SocketApi #3057
|
||||||
|
* SyncEngine: Show more timing measurements #3064
|
||||||
|
* Discovery: Add warning if returned etag is 0
|
||||||
|
* Fix a crash caused by an invalid DiscoveryDirectoryResult::iterator #3051
|
||||||
|
* Sync: Fix sync of deletions during 503. #2894
|
||||||
|
* Handle redirect of auth request. #3082
|
||||||
|
* Discovery: Fix parsing of broken XML replies, which fixes local file disappearing #3102
|
||||||
|
* Migration: Silently restore files that were deleted locally by bug #3102
|
||||||
|
* Sort folder sizes SelectiveSyncTreeView numerically #3112
|
||||||
|
* Sync: PropagateDownload: Read the mtime from the file system after writing it #3103
|
||||||
|
* Sync: Propagate download: Fix restoring files for which the conflict file exists #3106
|
||||||
|
* Use identical User Agents and version for csync and the Qt parts
|
||||||
|
* Prevent another crash in ~SocketApi #3118
|
||||||
|
* Windows: Fix rename of finished file. #3073
|
||||||
|
* AccountWizard: Fix auth error handling. #3155
|
||||||
|
* Documentation fixes
|
||||||
|
* Infrastructure/build fixes
|
||||||
|
* Win32/OS X: Apply patch from OpenSSL to handle oudated intermediates gracefully #3087
|
||||||
|
|
||||||
|
version 1.8.0 (release 2015-03-17)
|
||||||
* Mac OS: HIDPI support
|
* Mac OS: HIDPI support
|
||||||
* Support Sharing from desktop: Added a share dialog that can be
|
* Support Sharing from desktop: Added a share dialog that can be
|
||||||
opened by context menu in the file managers (Win, Mac, Nautilus)
|
opened by context menu in the file managers (Win, Mac, Nautilus)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 1 )
|
set( MIRALL_VERSION_MAJOR 1 )
|
||||||
set( MIRALL_VERSION_MINOR 8 )
|
set( MIRALL_VERSION_MINOR 8 )
|
||||||
set( MIRALL_VERSION_PATCH 0 )
|
set( MIRALL_VERSION_PATCH 1 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ if [ ! -z "$identity" ]; then
|
|||||||
echo "Will try to sign the installer"
|
echo "Will try to sign the installer"
|
||||||
pushd $install_path
|
pushd $install_path
|
||||||
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
||||||
mv "$installer_file".new $installer_file
|
mv "$installer_file".new "$installer_file"
|
||||||
popd
|
popd
|
||||||
else
|
else
|
||||||
echo "No certificate given, will not sign the pkg"
|
echo "No certificate given, will not sign the pkg"
|
||||||
|
|||||||
@@ -260,12 +260,18 @@ def CopyFramework(path):
|
|||||||
commands.append(args)
|
commands.append(args)
|
||||||
args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])]
|
args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
args = ['chmod', 'u+w', os.path.join(frameworks_dir, framework, "Resources")]
|
resources_dir = os.path.join(frameworks_dir, framework, "Resources")
|
||||||
|
|
||||||
|
args = ['mkdir', resources_dir]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['chmod', 'u+w', resources_dir]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
|
|
||||||
info_plist = os.path.join(os.path.split(path)[0], '..', '..', 'Contents', 'Info.plist')
|
info_plist = os.path.join(os.path.split(path)[0], '..', '..', 'Contents', 'Info.plist')
|
||||||
|
if not os.path.exists(info_plist):
|
||||||
|
info_plist = os.path.join(os.path.split(path)[0], 'Resources', 'Info.plist')
|
||||||
if os.path.exists(info_plist):
|
if os.path.exists(info_plist):
|
||||||
args = ['cp', '-r', info_plist, os.path.join(frameworks_dir, framework, "Resources")]
|
args = ['cp', '-r', info_plist, resources_dir]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
return os.path.join(full_path, parts[-1])
|
return os.path.join(full_path, parts[-1])
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh -x
|
#!/bin/sh -xe
|
||||||
|
|
||||||
[ "$#" -lt 2 ] && echo "Usage: sign_app.sh <app> <identity>" && exit
|
[ "$#" -lt 2 ] && echo "Usage: sign_app.sh <app> <identity>" && exit
|
||||||
|
|
||||||
@@ -7,6 +7,6 @@ identity="$2"
|
|||||||
|
|
||||||
codesign -s "$identity" --force --verbose=4 --deep "$src_app"
|
codesign -s "$identity" --force --verbose=4 --deep "$src_app"
|
||||||
|
|
||||||
# Just for our debug purposes:
|
# Verify the signature
|
||||||
spctl -a -t exec -vv $src_app
|
spctl -a -t exec -vv $src_app
|
||||||
codesign -dv $src_app
|
codesign -dv $src_app
|
||||||
|
|||||||
19
admin/win/docker/build.sh
Executable file
19
admin/win/docker/build.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
echo "Usage: $(basename $0) directory_relative_to_home [uid]"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
useradd user -u ${2:-1000}
|
||||||
|
su - user << EOF
|
||||||
|
cd /home/user/$1
|
||||||
|
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 .
|
||||||
|
EOF
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#VS2013
|
#VS2013
|
||||||
base_url=http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3
|
base_url=http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3
|
||||||
tmp_path=/tmp/.vcredist
|
tmp_path=${1:-/tmp/.vcredist}
|
||||||
|
|
||||||
mkdir -p $tmp_path
|
mkdir -p $tmp_path
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstal.lar ${APPLICATION_NAME}"
|
|||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstal.lar ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstal.lar ${APPLICATION_NAME}"
|
||||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolliu l'opció de manteniment per executar-ho."
|
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolliu l'opció de manteniment per executar-ho."
|
||||||
StrCpy $SEC_APPLICATION_DETAILS "Instal·lant ${APPLICATION_NAME} essencial."
|
StrCpy $SEC_APPLICATION_DETAILS "Instal·lant ${APPLICATION_NAME} essencial."
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integració per Windows Explorer"
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instal·lant integració per Windows Explorer"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Accés directe del programa al menú d'inici"
|
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Accés directe del programa al menú d'inici"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Afegint la drecera per ${APPLICATION_NAME} al menú d'inici."
|
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Afegint la drecera per ${APPLICATION_NAME} al menú d'inici."
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Drecera a l'escriptori"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Drecera a l'escriptori"
|
||||||
@@ -42,5 +44,3 @@ StrCpy $INIT_INSTALLER_RUNNING "L'instal·lador ja s'està executant."
|
|||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Aquest desinstal·lador requereix accés d'administrador, intenteu-ho de nou."
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Aquest desinstal·lador requereix accés d'administrador, intenteu-ho de nou."
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
||||||
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
|
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Afficher les notes de version"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Afficher les notes de version"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Le(s) processus en cours d’exécution ${APPLICATION_EXECUTABLE} doit (doivent) être stoppé(s) afin de poursuivre.$\nVoulez-vous que le programme d’installation s’en charge pour vous ?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Les processus ${APPLICATION_EXECUTABLE} en cours d’exécution doivent être stoppés avant de poursuivre.$\nVoulez-vous que le programme d’installation s’en charge pour vous ?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Fermeture des processus ${APPLICATION_EXECUTABLE}."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Fermeture des processus ${APPLICATION_EXECUTABLE}."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Le processus à stopper n'a pas été trouvé !"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Le processus à stopper n'a pas été trouvé !"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Une ancienne version de ${APPLICATION_NAME} est installée sur votre système. Il est recommandé de désinstaller cette version avant de continuer. Sélectionnez l'opération que vous voulez exécuter et cliquez sur Suivant pour continuer."
|
StrCpy $PageReinstall_NEW_Field_1 "Une ancienne version de ${APPLICATION_NAME} est installée sur votre système. Il est recommandé de désinstaller cette version avant de continuer. Sélectionnez l'opération que vous voulez exécuter et cliquez sur Suivant pour continuer."
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ StrCpy $UNINSTALL_ABORT "A desinstalaci
|
|||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Acceso de inicio rápido (n/d)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Acceso de inicio rápido (n/d)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Atallo no escritorio (sobrescribe o existente)"
|
StrCpy $INIT_NO_DESKTOP "Atallo no escritorio (sobrescribe o existente)"
|
||||||
StrCpy $UAC_ERROR_ELEVATE "Non foi posíbel elevalo, erro:"
|
StrCpy $UAC_ERROR_ELEVATE "Non foi posíbel elevalo, erro:"
|
||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador require acceso de administrador, tenteo de novo"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador require acceso de administrador, ténteo de novo"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "O instalador xa está en execución."
|
StrCpy $INIT_INSTALLER_RUNNING "O instalador xa está en execución."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este desinstalador require acceso de administrador, tenteo de novo"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este desinstalador require acceso de administrador, ténteo de novo"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "O desinstalador xa está en execución."
|
StrCpy $INIT_UNINSTALLER_RUNNING "O desinstalador xa está en execución."
|
||||||
StrCpy $SectionGroup_Shortcuts "Atallos"
|
StrCpy $SectionGroup_Shortcuts "Atallos"
|
||||||
|
|||||||
2
binary
2
binary
Submodule binary updated: 01d73965dc...1fb9ddfa9a
@@ -3,13 +3,7 @@
|
|||||||
# global needed variables
|
# global needed variables
|
||||||
set(APPLICATION_NAME "ocsync")
|
set(APPLICATION_NAME "ocsync")
|
||||||
|
|
||||||
set(APPLICATION_VERSION_MAJOR "0")
|
set(LIBRARY_VERSION ${MIRALL_VERSION})
|
||||||
set(APPLICATION_VERSION_MINOR "91")
|
|
||||||
set(APPLICATION_VERSION_PATCH "5")
|
|
||||||
|
|
||||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
|
||||||
|
|
||||||
set(LIBRARY_VERSION "0.2.1")
|
|
||||||
set(LIBRARY_SOVERSION "0")
|
set(LIBRARY_SOVERSION "0")
|
||||||
|
|
||||||
# add definitions
|
# add definitions
|
||||||
|
|||||||
@@ -576,7 +576,8 @@ int csync_commit(CSYNC *ctx) {
|
|||||||
_csync_clean_ctx(ctx);
|
_csync_clean_ctx(ctx);
|
||||||
|
|
||||||
ctx->remote.read_from_db = 0;
|
ctx->remote.read_from_db = 0;
|
||||||
ctx->read_from_db_disabled = 0;
|
ctx->read_remote_from_db = true;
|
||||||
|
ctx->db_is_empty = false;
|
||||||
|
|
||||||
|
|
||||||
/* Create new trees */
|
/* Create new trees */
|
||||||
@@ -773,10 +774,3 @@ int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int csync_set_read_from_db(CSYNC* ctx, int enabled)
|
|
||||||
{
|
|
||||||
ctx->read_from_db_disabled = !enabled;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <config_csync.h>
|
#include <config_csync.h>
|
||||||
|
|
||||||
#include "csync_version.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -550,11 +548,6 @@ void csync_resume(CSYNC *ctx);
|
|||||||
*/
|
*/
|
||||||
int csync_abort_requested(CSYNC *ctx);
|
int csync_abort_requested(CSYNC *ctx);
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
|
|
||||||
*/
|
|
||||||
int csync_set_read_from_db(CSYNC* ctx, int enabled);
|
|
||||||
|
|
||||||
char *csync_normalize_etag(const char *);
|
char *csync_normalize_etag(const char *);
|
||||||
time_t oc_httpdate_parse( const char *date );
|
time_t oc_httpdate_parse( const char *date );
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "csync_private.h"
|
#include "csync_private.h"
|
||||||
|
|
||||||
|
#include "csync_version.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* helper method to build up a user text for SSL problems, called from the
|
* helper method to build up a user text for SSL problems, called from the
|
||||||
@@ -437,8 +439,8 @@ int dav_connect(CSYNC *csyncCtx, const char *base_url) {
|
|||||||
// Should never take more than some seconds, 30 is really a max.
|
// Should never take more than some seconds, 30 is really a max.
|
||||||
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
|
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
|
||||||
|
|
||||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) mirall/%s (csyncoC)",
|
||||||
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
CSYNC_STRINGIFY( MIRALL_VERSION ), csync_owncloud_get_platform() );
|
||||||
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
||||||
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,17 @@ struct csync_s {
|
|||||||
int status;
|
int status;
|
||||||
volatile int abort;
|
volatile int abort;
|
||||||
void *rename_info;
|
void *rename_info;
|
||||||
int read_from_db_disabled;
|
|
||||||
|
/**
|
||||||
|
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
|
||||||
|
*/
|
||||||
|
bool read_remote_from_db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the DB is considered empty and all reads are skipped. (default is false)
|
||||||
|
* This is useful during the initial local discovery as it speeds it up significantly.
|
||||||
|
*/
|
||||||
|
bool db_is_empty;
|
||||||
|
|
||||||
struct csync_owncloud_ctx_s *owncloud_context;
|
struct csync_owncloud_ctx_s *owncloud_context;
|
||||||
|
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( tmp ) {
|
if( tmp ) {
|
||||||
if( tmp->path ) {
|
len = strlen( tmp->path );
|
||||||
len = strlen( tmp->path );
|
if( len > 0 ) {
|
||||||
h = c_jhash64((uint8_t *) tmp->path, len, 0);
|
h = c_jhash64((uint8_t *) tmp->path, len, 0);
|
||||||
/* First, check that the file is NOT in our tree (another file with the same name was added) */
|
/* First, check that the file is NOT in our tree (another file with the same name was added) */
|
||||||
node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
|
node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
|
|||||||
csync_file_stat_t *st = NULL;
|
csync_file_stat_t *st = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( !ctx ) {
|
if( !ctx || ctx->db_is_empty ) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !ctx ) {
|
if( !ctx || ctx->db_is_empty ) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +381,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !ctx ) {
|
if( !ctx || ctx->db_is_empty ) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +448,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !ctx ) {
|
if( !ctx || ctx->db_is_empty ) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
||||||
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
||||||
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
||||||
&& !metadata_differ && !ctx->read_from_db_disabled) {
|
&& !metadata_differ && ctx->read_remote_from_db) {
|
||||||
/* If both etag and file id are equal for a directory, read all contents from
|
/* If both etag and file id are equal for a directory, read all contents from
|
||||||
* the database.
|
* the database.
|
||||||
* The metadata comparison ensure that we fetch all the file id or permission when
|
* The metadata comparison ensure that we fetch all the file id or permission when
|
||||||
|
|||||||
@@ -28,22 +28,7 @@ extern "C" {
|
|||||||
#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s)
|
#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s)
|
||||||
#define CSYNC_TOSTRING(s) #s
|
#define CSYNC_TOSTRING(s) #s
|
||||||
|
|
||||||
/* csync version macros */
|
#define MIRALL_VERSION @MIRALL_VERSION@
|
||||||
#define CSYNC_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c))
|
|
||||||
#define CSYNC_VERSION_DOT(a, b, c) a ##.## b ##.## c
|
|
||||||
#define CSYNC_VERSION(a, b, c) CSYNC_VERSION_DOT(a, b, c)
|
|
||||||
|
|
||||||
/* csync version */
|
|
||||||
#define LIBCSYNC_VERSION_MAJOR @APPLICATION_VERSION_MAJOR@
|
|
||||||
#define LIBCSYNC_VERSION_MINOR @APPLICATION_VERSION_MINOR@
|
|
||||||
#define LIBCSYNC_VERSION_MICRO @APPLICATION_VERSION_PATCH@
|
|
||||||
|
|
||||||
#define LIBCSYNC_VERSION_INT CSYNC_VERSION_INT(LIBCSYNC_VERSION_MAJOR, \
|
|
||||||
LIBCSYNC_VERSION_MINOR, \
|
|
||||||
LIBCSYNC_VERSION_MICRO)
|
|
||||||
#define LIBCSYNC_VERSION CSYNC_VERSION(LIBCSYNC_VERSION_MAJOR, \
|
|
||||||
LIBCSYNC_VERSION_MINOR, \
|
|
||||||
LIBCSYNC_VERSION_MICRO)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "c_lib.h"
|
#include "c_lib.h"
|
||||||
#include "csync.h"
|
#include "csync.h"
|
||||||
|
#include "csync_log.h"
|
||||||
|
|
||||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||||
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||||
@@ -30,7 +31,9 @@ csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
|||||||
csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
|
csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
|
||||||
csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
|
csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
|
||||||
memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
|
memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
|
||||||
file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
|
if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||||
|
file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
|
||||||
|
}
|
||||||
if (file_stat_cpy->directDownloadCookies) {
|
if (file_stat_cpy->directDownloadCookies) {
|
||||||
file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
|
file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
|
||||||
}
|
}
|
||||||
@@ -68,6 +71,7 @@ void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* sr
|
|||||||
void csync_vio_set_file_id( char* dst, const char *src ) {
|
void csync_vio_set_file_id( char* dst, const char *src ) {
|
||||||
if( src && dst ) {
|
if( src && dst ) {
|
||||||
if( strlen(src) > FILE_ID_BUF_SIZE ) {
|
if( strlen(src) > FILE_ID_BUF_SIZE ) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src);
|
||||||
strcpy(dst, "");
|
strcpy(dst, "");
|
||||||
} else {
|
} else {
|
||||||
strcpy(dst, src);
|
strcpy(dst, src);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
==============
|
||||||
Advanced Usage
|
Advanced Usage
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
=====================
|
||||||
The Automatic Updater
|
The Automatic Updater
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@@ -9,11 +10,15 @@ users only need to use their normal package managers. However, on Linux systems
|
|||||||
the Updater will check for updates and notify you when a new version is
|
the Updater will check for updates and notify you when a new version is
|
||||||
available.
|
available.
|
||||||
|
|
||||||
|
.. note:: Because of various technical issues, desktop sync clients older than
|
||||||
|
1.7 will not be allowed to connect and sync with the ownCloud 8.1 server. It is
|
||||||
|
highly recommended to keep your client updated.
|
||||||
|
|
||||||
Basic Workflow
|
Basic Workflow
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The following sections describe how to use the Automatic Updater on different
|
The following sections describe how to use the Automatic Updater on different
|
||||||
operating systems:
|
operating systems.
|
||||||
|
|
||||||
Windows
|
Windows
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
@@ -26,6 +31,9 @@ If an update is available, and has been successfully downloaded, the ownCloud
|
|||||||
client starts a silent update prior to its next launch and then restarts
|
client starts a silent update prior to its next launch and then restarts
|
||||||
itself. Should the silent update fail, the client offers a manual download.
|
itself. Should the silent update fail, the client offers a manual download.
|
||||||
|
|
||||||
|
When you upgrade from 1.7 you should restart Windows to ensure that all the new
|
||||||
|
features in 1.8 are enabled.
|
||||||
|
|
||||||
.. note:: Administrative privileges are required to perform the update.
|
.. note:: Administrative privileges are required to perform the update.
|
||||||
|
|
||||||
Mac OS X
|
Mac OS X
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ and then use their package managers to install the desktop sync client. Linux
|
|||||||
users will also update their sync clients via package manager, and the client
|
users will also update their sync clients via package manager, and the client
|
||||||
will display a notification when an update is available.
|
will display a notification when an update is available.
|
||||||
|
|
||||||
|
Linux users must also have a password manager enabled, such as GNOME Keyring or
|
||||||
|
KWallet, so that the sync client can login automatically.
|
||||||
|
|
||||||
Improvements and New Features
|
Improvements and New Features
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
@@ -32,6 +35,9 @@ including:
|
|||||||
and Nautilus on Linux.
|
and Nautilus on Linux.
|
||||||
* Faster uploads and downloads.
|
* Faster uploads and downloads.
|
||||||
|
|
||||||
|
.. note:: When you upgrade from 1.7, restart Windows to ensure that all new
|
||||||
|
features are visible.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,6 @@ Desktop Sync client enables you to:
|
|||||||
Your files are always automatically synchronized between your ownCloud server
|
Your files are always automatically synchronized between your ownCloud server
|
||||||
and local PC.
|
and local PC.
|
||||||
|
|
||||||
|
.. note:: Because of various technical issues, desktop sync clients older than
|
||||||
|
1.7 will not allowed to connect and sync with the ownCloud 8.1 server. It is
|
||||||
|
highly recommended to keep your client updated.
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
When invoking the client from the command line, the following options are supported:
|
You have the option of starting your ownCloud desktop client with the
|
||||||
|
``owncloud`` command. The following options are supported:
|
||||||
|
|
||||||
``-h``, ``--help``
|
``owncloud -h`` or ``owncloud --help``
|
||||||
Displays all command options.
|
Displays all command options.
|
||||||
|
|
||||||
|
The other options are:
|
||||||
|
|
||||||
``--logwindow``
|
``--logwindow``
|
||||||
Opens a window displaying log output.
|
Opens a window displaying log output.
|
||||||
|
|
||||||
``--logfile`` `<filename>`
|
``--logfile`` `<filename>`
|
||||||
Write log output to the file specified. To write to stdout, specify `-` as the filename.
|
Write log output to the file specified. To write to stdout, specify `-`
|
||||||
|
as the filename.
|
||||||
|
|
||||||
``--logdir`` `<name>`
|
``--logdir`` `<name>`
|
||||||
Writes each synchronization log output in a new file in the specified directory.
|
Writes each synchronization log output in a new file in the specified
|
||||||
|
directory.
|
||||||
|
|
||||||
``--logexpire`` `<hours>`
|
``--logexpire`` `<hours>`
|
||||||
Removes logs older than the value specified (in hours). This command is used with ``--logdir``.
|
Removes logs older than the value specified (in hours). This command is
|
||||||
|
used with ``--logdir``.
|
||||||
|
|
||||||
``--logflush``
|
``--logflush``
|
||||||
Clears (flushes) the log file after each write action.
|
Clears (flushes) the log file after each write action.
|
||||||
|
|
||||||
``--confdir`` `<dirname>`
|
``--confdir`` `<dirname>`
|
||||||
Uses the specified configuration directory.
|
Uses the specified configuration directory.
|
||||||
|
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
The ownCloud Client packages contain a command line client that can be used to
|
The ownCloud Client packages contain a command line client, ``owncloudcmd``, that can
|
||||||
synchronize ownCloud files to client machines. The command line client is
|
be used to synchronize ownCloud files to client machines.
|
||||||
called ``owncloudcmd``.
|
|
||||||
|
|
||||||
owncloudcmd performs a single *sync run* and then exits the synchronization
|
``owncloudcmd`` performs a single *sync run* and then exits the synchronization
|
||||||
process. In this manner, owncloudcmd processes the differences between client
|
process. In this manner, ``owncloudcmd`` processes the differences between
|
||||||
and server directories and propagates the files to bring both repositories to
|
client and server directories and propagates the files to bring both
|
||||||
the same state. Contrary to the GUI-based client, ``owncloudcmd`` does not
|
repositories to the same state. Contrary to the GUI-based client,
|
||||||
repeat
|
``owncloudcmd`` does not repeat synchronizations on its own. It also does not
|
||||||
synchronizations on its own. It also does not monitor for file system changes.
|
monitor for file system changes.
|
||||||
|
|
||||||
To invoke ``owncloudcmd``, you must provide the local and the remote
|
To invoke ``owncloudcmd``, you must provide the local and the remote repository
|
||||||
repository
|
|
||||||
URL using the following command::
|
URL using the following command::
|
||||||
|
|
||||||
owncloudcmd [OPTIONS...] sourcedir owncloudurl
|
owncloudcmd [OPTIONS...] sourcedir owncloudurl
|
||||||
@@ -18,45 +16,41 @@ URL using the following command::
|
|||||||
where ``sourcedir`` is the local directory and ``owncloudurl`` is
|
where ``sourcedir`` is the local directory and ``owncloudurl`` is
|
||||||
the server URL.
|
the server URL.
|
||||||
|
|
||||||
.. note:: Prior to the 1.6 version of owncloudcmd, the tool only accepted
|
Other command line switches supported by ``owncloudcmd`` include the following:
|
||||||
``owncloud://`` or ``ownclouds://`` in place of ``http://`` and ``https://`` as
|
|
||||||
a scheme. See ``Examples`` for details.
|
|
||||||
|
|
||||||
Other comand line switches supported by owncloudcmd include the following:
|
|
||||||
|
|
||||||
``--user``, ``-u`` ``[user]``
|
``--user``, ``-u`` ``[user]``
|
||||||
Use ``user`` as the login name.
|
Specify the user's login name.
|
||||||
|
|
||||||
``--password``, ``-p`` ``[password]``
|
``--password``, ``-p`` ``[password]``
|
||||||
Use ``password`` as the password.
|
Specify the user's password.
|
||||||
|
|
||||||
``-n``
|
``-n``
|
||||||
Use ``netrc (5)`` for login.
|
Use ``netrc (5)`` for login.
|
||||||
|
|
||||||
``--non-interactive``
|
``--non-interactive``
|
||||||
Do not prompt for questions.
|
Do not prompt for questions.
|
||||||
|
|
||||||
``--silent``, ``-s``
|
``--silent``, ``-s``
|
||||||
Inhibits verbose log output.
|
Inhibits verbose log output.
|
||||||
|
|
||||||
``--trust``
|
``--trust``
|
||||||
Trust any SSL certificate, including invalid ones.
|
Trust any SSL certificate, including invalid ones.
|
||||||
|
|
||||||
``--httpproxy http://[user@pass:]<server>:<port>``
|
``--httpproxy http://[user@pass:]<server>:<port>``
|
||||||
Uses the specified ``server`` as the HTTP proxy.
|
Uses the specified ``server`` as the HTTP proxy.
|
||||||
|
|
||||||
|
``--unsyncedfolders [file]``
|
||||||
|
File containing list of folders to not sync
|
||||||
|
|
||||||
Credential Handling
|
Credential Handling
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
By default, ``owncloudcmd`` reads the client configuration and uses the
|
By default, ``owncloudcmd`` reads the client configuration and uses the
|
||||||
credentials of the GUI synchronization client. If no client is configured, or if you choose
|
credentials of the GUI synchronization client. If no client is configured, or if
|
||||||
to use a different user to synchronize, you can specify the user password
|
you choose to use a different user to synchronize, you can specify the user
|
||||||
setting with the usual URL pattern. For example::
|
password setting with the usual URL pattern. For example::
|
||||||
|
|
||||||
https://user:secret@192.168.178.2/remote.php/webdav
|
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
|
||||||
|
|
||||||
Example
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
To synchronize the ownCloud directory ``Music`` to the local directory
|
To synchronize the ownCloud directory ``Music`` to the local directory
|
||||||
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
||||||
@@ -66,13 +60,5 @@ machine using IP address ``192.168.178.1``, the command line would be::
|
|||||||
$HOME/media/music \
|
$HOME/media/music \
|
||||||
https://server/owncloud/remote.php/webdav/Music
|
https://server/owncloud/remote.php/webdav/Music
|
||||||
|
|
||||||
``owncloudcmd`` will enquire user name and password, unless they have
|
``owncloudcmd`` will prompt for the user name and password, unless they have
|
||||||
been specified on the command line or ``-n`` has been passed.
|
been specified on the command line or ``-n`` has been passed.
|
||||||
|
|
||||||
Using the legacy scheme, the command line would be::
|
|
||||||
|
|
||||||
$ owncloudcmd --httpproxy http://192.168.178.1:8080 \
|
|
||||||
$HOME/media/music \
|
|
||||||
ownclouds://server/owncloud/remote.php/webdav/Music
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class SocketConnect(GObject.GObject):
|
|||||||
print("Sending failed.")
|
print("Sending failed.")
|
||||||
self.reconnect()
|
self.reconnect()
|
||||||
else:
|
else:
|
||||||
print "Cannot send, not connected!"
|
print("Cannot send, not connected!")
|
||||||
|
|
||||||
def addListener(self, listener):
|
def addListener(self, listener):
|
||||||
self._listeners.append(listener)
|
self._listeners.append(listener)
|
||||||
@@ -85,7 +85,7 @@ class SocketConnect(GObject.GObject):
|
|||||||
self.connected = True
|
self.connected = True
|
||||||
print("Setting connected to %r" % self.connected )
|
print("Setting connected to %r" % self.connected )
|
||||||
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
||||||
print "Socket watch id: "+str(self._watch_id)
|
print("Socket watch id: "+str(self._watch_id))
|
||||||
return False # don't run again
|
return False # don't run again
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Could not connect to unix socket." + str(e))
|
print("Could not connect to unix socket." + str(e))
|
||||||
@@ -175,7 +175,7 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
|||||||
|
|
||||||
def menu_share(self, menu, file):
|
def menu_share(self, menu, file):
|
||||||
filename = get_local_path(file.get_uri())
|
filename = get_local_path(file.get_uri())
|
||||||
print "Share file "+filename
|
print("Share file "+filename)
|
||||||
socketConnect.sendCommand("SHARE:"+filename+"\n")
|
socketConnect.sendCommand("SHARE:"+filename+"\n")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,6 @@
|
|||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -101,8 +100,8 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@@ -132,6 +131,7 @@
|
|||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalLibraryDirectories>..\$(Configuration)\$(Platform);</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>..\$(Configuration)\$(Platform);</AdditionalLibraryDirectories>
|
||||||
|
|||||||
@@ -127,6 +127,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
@@ -145,6 +146,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|||||||
@@ -120,6 +120,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
@@ -136,6 +137,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "qtlocalpeer.h"
|
#include "qtlocalpeer.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QDataStream>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
|||||||
@@ -194,6 +194,9 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
|
|||||||
if (options->target_url.startsWith("http"))
|
if (options->target_url.startsWith("http"))
|
||||||
options->target_url.replace(0, 4, "owncloud");
|
options->target_url.replace(0, 4, "owncloud");
|
||||||
options->source_dir = args.takeLast();
|
options->source_dir = args.takeLast();
|
||||||
|
if (!options->source_dir.endsWith('/')) {
|
||||||
|
options->source_dir.append('/');
|
||||||
|
}
|
||||||
if( !QFile::exists( options->source_dir )) {
|
if( !QFile::exists( options->source_dir )) {
|
||||||
std::cerr << "Source dir '" << qPrintable(options->source_dir) << "' does not exist." << std::endl;
|
std::cerr << "Source dir '" << qPrintable(options->source_dir) << "' does not exist." << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -442,7 +445,9 @@ restart_sync:
|
|||||||
if (!f.open(QFile::ReadOnly)) {
|
if (!f.open(QFile::ReadOnly)) {
|
||||||
qCritical() << "Could not open file containing the list of unsynced folders: " << options.unsyncedfolders;
|
qCritical() << "Could not open file containing the list of unsynced folders: " << options.unsyncedfolders;
|
||||||
} else {
|
} else {
|
||||||
selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n');
|
// filter out empty lines and comments
|
||||||
|
selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n').filter(QRegExp("\\S+")).filter(QRegExp("^[^#]"));
|
||||||
|
|
||||||
for (int i = 0; i < selectiveSyncList.count(); ++i) {
|
for (int i = 0; i < selectiveSyncList.count(); ++i) {
|
||||||
if (!selectiveSyncList.at(i).endsWith(QLatin1Char('/'))) {
|
if (!selectiveSyncList.at(i).endsWith(QLatin1Char('/'))) {
|
||||||
selectiveSyncList[i].append(QLatin1Char('/'));
|
selectiveSyncList[i].append(QLatin1Char('/'));
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "simplesslerrorhandler.h"
|
#include "simplesslerrorhandler.h"
|
||||||
|
|
||||||
bool SimpleSslErrorHandler::handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, OCC::AccountPtr account)
|
bool SimpleSslErrorHandler::handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr account)
|
||||||
{
|
{
|
||||||
(void) account;
|
(void) account;
|
||||||
|
(void) conf;
|
||||||
|
|
||||||
if (!certs) {
|
if (!certs) {
|
||||||
qDebug() << "Certs parameter required but is NULL!";
|
qDebug() << "Certs parameter required but is NULL!";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class QSslCertificate;
|
|||||||
|
|
||||||
class SimpleSslErrorHandler : public OCC::AbstractSslErrorHandler {
|
class SimpleSslErrorHandler : public OCC::AbstractSslErrorHandler {
|
||||||
public:
|
public:
|
||||||
bool handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, OCC::AccountPtr) Q_DECL_OVERRIDE;
|
bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr) Q_DECL_OVERRIDE;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SIMPLESSLERRORHANDLER_H
|
#endif // SIMPLESSLERRORHANDLER_H
|
||||||
|
|||||||
@@ -154,10 +154,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
|
|||||||
|
|
||||||
qt_add_translation(client_I18N ${TRANSLATIONS})
|
qt_add_translation(client_I18N ${TRANSLATIONS})
|
||||||
|
|
||||||
|
IF( WIN32 )
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||||
|
@ONLY)
|
||||||
|
set(client_version ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
set( final_src
|
set( final_src
|
||||||
${MIRALL_RC_SRC}
|
${MIRALL_RC_SRC}
|
||||||
${client_SRCS}
|
${client_SRCS}
|
||||||
${client_UI_SRCS}
|
${client_UI_SRCS}
|
||||||
|
${client_version}
|
||||||
${guiMoc}
|
${guiMoc}
|
||||||
${client_I18N}
|
${client_I18N}
|
||||||
${3rdparty_SRC}
|
${3rdparty_SRC}
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ public:
|
|||||||
* @return the list of migrated folder definitions
|
* @return the list of migrated folder definitions
|
||||||
*/
|
*/
|
||||||
QStringList migrateFolderDefinitons();
|
QStringList migrateFolderDefinitons();
|
||||||
signals:
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ void AccountStateManager::setAccountState(AccountState *accountState)
|
|||||||
emit accountStateRemoved(_accountState);
|
emit accountStateRemoved(_accountState);
|
||||||
}
|
}
|
||||||
_accountState = accountState;
|
_accountState = accountState;
|
||||||
emit accountStateAdded(accountState);
|
if (accountState) {
|
||||||
|
emit accountStateAdded(accountState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountStateManager::slotAccountAdded(AccountPtr account)
|
void AccountStateManager::slotAccountAdded(AccountPtr account)
|
||||||
@@ -54,13 +56,15 @@ void AccountStateManager::slotAccountAdded(AccountPtr account)
|
|||||||
AccountState::AccountState(AccountPtr account)
|
AccountState::AccountState(AccountPtr account)
|
||||||
: QObject(account.data())
|
: QObject(account.data())
|
||||||
, _account(account)
|
, _account(account)
|
||||||
, _quotaInfo(new QuotaInfo(this))
|
, _quotaInfo(0)
|
||||||
, _state(AccountState::Disconnected)
|
, _state(AccountState::Disconnected)
|
||||||
, _connectionStatus(ConnectionValidator::Undefined)
|
, _connectionStatus(ConnectionValidator::Undefined)
|
||||||
, _waitingForNewCredentials(false)
|
, _waitingForNewCredentials(false)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<AccountState*>("AccountState*");
|
qRegisterMetaType<AccountState*>("AccountState*");
|
||||||
|
|
||||||
|
_quotaInfo = new QuotaInfo(this); // Need to be initialized when 'this' is fully initialized
|
||||||
|
|
||||||
connect(account.data(), SIGNAL(invalidCredentials()),
|
connect(account.data(), SIGNAL(invalidCredentials()),
|
||||||
SLOT(slotInvalidCredentials()));
|
SLOT(slotInvalidCredentials()));
|
||||||
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
|
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
|
||||||
@@ -179,6 +183,15 @@ void AccountState::checkConnectivity()
|
|||||||
conValidator->checkAuthentication();
|
conValidator->checkAuthentication();
|
||||||
} else {
|
} else {
|
||||||
// Check the server and then the auth.
|
// Check the server and then the auth.
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// There seems to be a bug in Qt on Windows where QNAM sometimes stops
|
||||||
|
// working correctly after the computer woke up from sleep. See #2895 #2899
|
||||||
|
// and #2973.
|
||||||
|
// As an attempted workaround, reset the QNAM regularly if the account is
|
||||||
|
// disconnected.
|
||||||
|
account()->resetNetworkAccessManager();
|
||||||
|
#endif
|
||||||
conValidator->checkServerAndAuth();
|
conValidator->checkServerAndAuth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,8 @@ Application::Application(int &argc, char **argv) :
|
|||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
{
|
{
|
||||||
// qDebug() << "* OCC shutdown";
|
// Remove the account from the account manager so it can be deleted.
|
||||||
|
AccountManager::instance()->setAccount(AccountPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::slotLogin()
|
void Application::slotLogin()
|
||||||
@@ -403,7 +404,10 @@ void Application::parseOptions(const QStringList &options)
|
|||||||
} else if (option == QLatin1String("--confdir")) {
|
} else if (option == QLatin1String("--confdir")) {
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
QString confDir = it.next();
|
QString confDir = it.next();
|
||||||
ConfigFile::setConfDir( confDir );
|
if (!ConfigFile::setConfDir( confDir )) {
|
||||||
|
std::cerr << "Invalid path passed to --confdir" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showHelp();
|
showHelp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -772,6 +772,7 @@ void Folder::startSync(const QStringList &pathList)
|
|||||||
_timeSinceLastSyncStart.restart();
|
_timeSinceLastSyncStart.restart();
|
||||||
_syncResult.clearErrors();
|
_syncResult.clearErrors();
|
||||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||||
|
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||||
emit syncStateChange();
|
emit syncStateChange();
|
||||||
|
|
||||||
qDebug() << "*** Start syncing - client version"
|
qDebug() << "*** Start syncing - client version"
|
||||||
|
|||||||
@@ -873,6 +873,13 @@ void FolderMan::setDirtyProxy(bool value)
|
|||||||
foreach( Folder *f, _folderMap.values() ) {
|
foreach( Folder *f, _folderMap.values() ) {
|
||||||
if(f) {
|
if(f) {
|
||||||
f->setProxyDirty(value);
|
f->setProxyDirty(value);
|
||||||
|
|
||||||
|
if (f->accountState() && f->accountState()->account()
|
||||||
|
&& f->accountState()->account()->networkAccessManager()) {
|
||||||
|
// Need to do this have us not use the old determined system proxy
|
||||||
|
f->accountState()->account()->networkAccessManager()->setProxy(
|
||||||
|
QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,6 +246,12 @@ FolderWizardRemotePath::FolderWizardRemotePath(AccountPtr account)
|
|||||||
_lscolTimer.setInterval(500);
|
_lscolTimer.setInterval(500);
|
||||||
_lscolTimer.setSingleShot(true);
|
_lscolTimer.setSingleShot(true);
|
||||||
connect(&_lscolTimer, SIGNAL(timeout()), SLOT(slotLsColFolderEntry()));
|
connect(&_lscolTimer, SIGNAL(timeout()), SLOT(slotLsColFolderEntry()));
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
|
_ui.folderTreeWidget->header()->setSectionResizeMode(0,QHeaderView::ResizeToContents);
|
||||||
|
// Make sure that there will be a scrollbar when the contents is too wide
|
||||||
|
_ui.folderTreeWidget->header()->setStretchLastSection(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWizardRemotePath::slotAddRemoteFolder()
|
void FolderWizardRemotePath::slotAddRemoteFolder()
|
||||||
@@ -291,6 +297,8 @@ void FolderWizardRemotePath::slotCreateRemoteFolderFinished(QNetworkReply::Netwo
|
|||||||
qDebug() << "** webdav mkdir request finished";
|
qDebug() << "** webdav mkdir request finished";
|
||||||
showWarn(tr("Folder was successfully created on %1.").arg(Theme::instance()->appNameGUI()));
|
showWarn(tr("Folder was successfully created on %1.").arg(Theme::instance()->appNameGUI()));
|
||||||
slotRefreshFolders();
|
slotRefreshFolders();
|
||||||
|
_ui.folderEntry->setText(static_cast<MkColJob *>(sender())->path());
|
||||||
|
slotLsColFolderEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ IgnoreListEditor::IgnoreListEditor(QWidget *parent) :
|
|||||||
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
|
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
|
||||||
ui->removePushButton->setEnabled(false);
|
ui->removePushButton->setEnabled(false);
|
||||||
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
|
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
|
||||||
connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemChanged(QListWidgetItem*)));
|
|
||||||
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
|
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
|
||||||
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
|
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
|
||||||
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
|
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
|
|||||||
}
|
}
|
||||||
AccountPtr account = _ocWizard->account();
|
AccountPtr account = _ocWizard->account();
|
||||||
account->setUrl(url);
|
account->setUrl(url);
|
||||||
|
// Reset the proxy which might had been determined previously in ConnectionValidator::checkServerAndAuth()
|
||||||
|
// when there was a previous account.
|
||||||
|
account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||||
// Set fake credentials beforfe we check what credential it actually is.
|
// Set fake credentials beforfe we check what credential it actually is.
|
||||||
account->setCredentials(CredentialsFactory::create("dummy"));
|
account->setCredentials(CredentialsFactory::create("dummy"));
|
||||||
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), this);
|
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), this);
|
||||||
@@ -214,11 +217,71 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
|||||||
auto *job = new PropfindJob(account, "/", this);
|
auto *job = new PropfindJob(account, "/", this);
|
||||||
job->setIgnoreCredentialFailure(true);
|
job->setIgnoreCredentialFailure(true);
|
||||||
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
||||||
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
||||||
connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotConnectionCheck(QNetworkReply*)));
|
connect(job, SIGNAL(finishedWithError()), this, SLOT(slotAuthError()));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotAuthError()
|
||||||
|
{
|
||||||
|
QString errorMsg;
|
||||||
|
|
||||||
|
PropfindJob* job = qobject_cast<PropfindJob*>(sender());
|
||||||
|
if (!job) {
|
||||||
|
qWarning() << "Can't check for authed redirects. This slot should be invoked from PropfindJob!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QNetworkReply* reply = job->reply();
|
||||||
|
|
||||||
|
// If there were redirects on the *authed* requests, also store
|
||||||
|
// the updated server URL, similar to redirects on status.php.
|
||||||
|
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
|
if (!redirectUrl.isEmpty()) {
|
||||||
|
qDebug() << "authed request was redirected to" << redirectUrl.toString();
|
||||||
|
|
||||||
|
// strip the expected path
|
||||||
|
QString path = redirectUrl.path();
|
||||||
|
static QString expectedPath = "/" + _ocWizard->account()->davPath();
|
||||||
|
if (path.endsWith(expectedPath)) {
|
||||||
|
path.chop(expectedPath.size());
|
||||||
|
redirectUrl.setPath(path);
|
||||||
|
|
||||||
|
qDebug() << "setting account url to" << redirectUrl.toString();
|
||||||
|
_ocWizard->account()->setUrl(redirectUrl);
|
||||||
|
testOwnCloudConnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorMsg = tr("The authenticated request to the server was redirected to "
|
||||||
|
"'%1'. The URL is bad, the server is misconfigured.")
|
||||||
|
.arg(redirectUrl.toString());
|
||||||
|
|
||||||
|
// A 404 is actually a success: we were authorized to know that the folder does
|
||||||
|
// not exist. It will be created later...
|
||||||
|
} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
|
_ocWizard->successfulStep();
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Provide messages for other errors, such as invalid credentials.
|
||||||
|
} else if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
errorMsg = reply->errorString();
|
||||||
|
if (!_ocWizard->account()->credentials()->stillValid(reply)) {
|
||||||
|
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
|
||||||
|
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
||||||
|
.arg(_ocWizard->account()->url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something else went wrong, maybe the response was 200 but with invalid data.
|
||||||
|
} else {
|
||||||
|
errorMsg = tr("There was an invalid response to an authenticated webdav request");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ocWizard->show();
|
||||||
|
if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds) {
|
||||||
|
_ocWizard->back();
|
||||||
|
}
|
||||||
|
_ocWizard->displayError(errorMsg, _ocWizard->currentId() == WizardCommon::Page_ServerSetup && checkDowngradeAdvised(reply));
|
||||||
|
}
|
||||||
|
|
||||||
bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
||||||
{
|
{
|
||||||
if(reply->url().scheme() != QLatin1String("https")) {
|
if(reply->url().scheme() != QLatin1String("https")) {
|
||||||
@@ -242,29 +305,6 @@ bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotConnectionCheck(QNetworkReply* reply)
|
|
||||||
{
|
|
||||||
QString msg = reply->errorString();
|
|
||||||
switch (reply->error()) {
|
|
||||||
case QNetworkReply::NoError:
|
|
||||||
case QNetworkReply::ContentNotFoundError:
|
|
||||||
_ocWizard->successfulStep();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!_ocWizard->account()->credentials()->stillValid(reply)) {
|
|
||||||
msg = tr("Access forbidden by server. To verify that you have proper access, "
|
|
||||||
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
|
||||||
.arg(_ocWizard->account()->url().toString());
|
|
||||||
}
|
|
||||||
_ocWizard->show();
|
|
||||||
if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds) {
|
|
||||||
_ocWizard->back();
|
|
||||||
}
|
|
||||||
_ocWizard->displayError(msg, _ocWizard->currentId() == WizardCommon::Page_ServerSetup && checkDowngradeAdvised(reply));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
|
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
|
||||||
{
|
{
|
||||||
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
||||||
@@ -291,7 +331,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
|
|||||||
}
|
}
|
||||||
if (nextStep) {
|
if (nextStep) {
|
||||||
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), _ocWizard->account()->davPath() + remoteFolder, this);
|
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), _ocWizard->account()->davPath() + remoteFolder, this);
|
||||||
connect(job, SIGNAL(exists(QNetworkReply*)), SLOT(slotAuthCheckReply(QNetworkReply*)));
|
connect(job, SIGNAL(exists(QNetworkReply*)), SLOT(slotRemoteFolderExists(QNetworkReply*)));
|
||||||
job->start();
|
job->start();
|
||||||
} else {
|
} else {
|
||||||
finalizeSetup( false );
|
finalizeSetup( false );
|
||||||
@@ -299,7 +339,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ### TODO move into EntityExistsJob once we decide if/how to return gui strings from jobs
|
// ### TODO move into EntityExistsJob once we decide if/how to return gui strings from jobs
|
||||||
void OwncloudSetupWizard::slotAuthCheckReply(QNetworkReply *reply)
|
void OwncloudSetupWizard::slotRemoteFolderExists(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
QString error;
|
QString error;
|
||||||
@@ -519,8 +559,10 @@ bool DetermineAuthTypeJob::finished()
|
|||||||
} else if (redirection.toString().endsWith(account()->davPath())) {
|
} else if (redirection.toString().endsWith(account()->davPath())) {
|
||||||
// do a new run
|
// do a new run
|
||||||
_redirects++;
|
_redirects++;
|
||||||
|
resetTimeout();
|
||||||
setReply(getRequest(redirection));
|
setReply(getRequest(redirection));
|
||||||
setupConnections(reply());
|
setupConnections(reply());
|
||||||
|
return false; // don't discard
|
||||||
} else {
|
} else {
|
||||||
QRegExp shibbolethyWords("SAML|wayf");
|
QRegExp shibbolethyWords("SAML|wayf");
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ private slots:
|
|||||||
void slotNoOwnCloudFoundAuthTimeout(const QUrl&url);
|
void slotNoOwnCloudFoundAuthTimeout(const QUrl&url);
|
||||||
|
|
||||||
void slotConnectToOCUrl(const QString&);
|
void slotConnectToOCUrl(const QString&);
|
||||||
void slotConnectionCheck(QNetworkReply*);
|
void slotAuthError();
|
||||||
|
|
||||||
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
||||||
void slotAuthCheckReply(QNetworkReply*);
|
void slotRemoteFolderExists(QNetworkReply*);
|
||||||
void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError);
|
void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError);
|
||||||
void slotAssistantFinished( int );
|
void slotAssistantFinished( int );
|
||||||
void slotSkipFolderConfiguration();
|
void slotSkipFolderConfiguration();
|
||||||
|
|||||||
@@ -73,16 +73,10 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
|||||||
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
|
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
|
||||||
_copyBtn->setEnabled(false);
|
_copyBtn->setEnabled(false);
|
||||||
connect(_copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
|
connect(_copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
|
||||||
|
|
||||||
ConfigFile cfg;
|
|
||||||
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolWidget::~ProtocolWidget()
|
ProtocolWidget::~ProtocolWidget()
|
||||||
{
|
{
|
||||||
ConfigFile cfg;
|
|
||||||
cfg.saveGeometryHeader(_ui->_treeWidget->header() );
|
|
||||||
|
|
||||||
delete _ui;
|
delete _ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +131,20 @@ void ProtocolWidget::slotRetrySync()
|
|||||||
folderMan->slotScheduleAllFolders();
|
folderMan->slotScheduleAllFolders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolWidget::showEvent(QShowEvent *ev)
|
||||||
|
{
|
||||||
|
ConfigFile cfg;
|
||||||
|
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
|
||||||
|
QWidget::showEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolWidget::hideEvent(QHideEvent *ev)
|
||||||
|
{
|
||||||
|
ConfigFile cfg;
|
||||||
|
cfg.saveGeometryHeader(_ui->_treeWidget->header() );
|
||||||
|
QWidget::hideEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
||||||
{
|
{
|
||||||
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
||||||
@@ -159,16 +167,11 @@ void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
|||||||
|
|
||||||
QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format) const
|
QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format) const
|
||||||
{
|
{
|
||||||
QLocale loc = QLocale::system();
|
const QLocale loc = QLocale::system();
|
||||||
QString timeStr;
|
QString dtFormat = loc.dateTimeFormat(format);
|
||||||
|
static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
|
||||||
if( format == QLocale::NarrowFormat ) {
|
dtFormat.replace(re, "\\1:mm:ss");
|
||||||
timeStr = loc.toString(dt, QLocale::NarrowFormat);
|
return loc.toString(dt, dtFormat);
|
||||||
} else {
|
|
||||||
timeStr = loc.toString(dt, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
return timeStr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolWidget::slotOpenFile( QTreeWidgetItem *item, int )
|
void ProtocolWidget::slotOpenFile( QTreeWidgetItem *item, int )
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ public:
|
|||||||
explicit ProtocolWidget(QWidget *parent = 0);
|
explicit ProtocolWidget(QWidget *parent = 0);
|
||||||
~ProtocolWidget();
|
~ProtocolWidget();
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
|
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
|
||||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||||
@@ -49,6 +47,10 @@ protected slots:
|
|||||||
void copyToClipboard();
|
void copyToClipboard();
|
||||||
void slotRetrySync();
|
void slotRetrySync();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *);
|
||||||
|
void hideEvent(QHideEvent *);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void guiLog(const QString&, const QString&);
|
void guiLog(const QString&, const QString&);
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,33 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
|
||||||
|
class SelectiveSyncTreeViewItem : public QTreeWidgetItem {
|
||||||
|
public:
|
||||||
|
SelectiveSyncTreeViewItem(int type = QTreeWidgetItem::Type)
|
||||||
|
: QTreeWidgetItem(type) { }
|
||||||
|
SelectiveSyncTreeViewItem(const QStringList &strings, int type = QTreeWidgetItem::Type)
|
||||||
|
: QTreeWidgetItem(strings, type) { }
|
||||||
|
SelectiveSyncTreeViewItem(QTreeWidget *view, int type = QTreeWidgetItem::Type)
|
||||||
|
: QTreeWidgetItem(view, type) { }
|
||||||
|
SelectiveSyncTreeViewItem(QTreeWidgetItem *parent, int type = QTreeWidgetItem::Type)
|
||||||
|
: QTreeWidgetItem(parent, type) { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool operator<(const QTreeWidgetItem &other)const {
|
||||||
|
int column = treeWidget()->sortColumn();
|
||||||
|
if (column == 1) {
|
||||||
|
return data(1, Qt::UserRole).toLongLong() < other.data(1, Qt::UserRole).toLongLong();
|
||||||
|
}
|
||||||
|
return QTreeWidgetItem::operator <(other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||||
: QTreeWidget(parent), _inserting(false), _account(account)
|
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||||
{
|
{
|
||||||
@@ -101,9 +124,9 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
|||||||
parent->setToolTip(0, path);
|
parent->setToolTip(0, path);
|
||||||
parent->setData(0, Qt::UserRole, path);
|
parent->setData(0, Qt::UserRole, path);
|
||||||
} else {
|
} else {
|
||||||
QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
|
SelectiveSyncTreeViewItem *item = static_cast<SelectiveSyncTreeViewItem*>(findFirstChild(parent, pathTrail.first()));
|
||||||
if (!item) {
|
if (!item) {
|
||||||
item = new QTreeWidgetItem(parent);
|
item = new SelectiveSyncTreeViewItem(parent);
|
||||||
if (parent->checkState(0) == Qt::Checked
|
if (parent->checkState(0) == Qt::Checked
|
||||||
|| parent->checkState(0) == Qt::PartiallyChecked) {
|
|| parent->checkState(0) == Qt::PartiallyChecked) {
|
||||||
item->setCheckState(0, Qt::Checked);
|
item->setCheckState(0, Qt::Checked);
|
||||||
@@ -138,7 +161,7 @@ void SelectiveSyncTreeView::slotUpdateDirectories(const QStringList&list)
|
|||||||
QScopedValueRollback<bool> isInserting(_inserting);
|
QScopedValueRollback<bool> isInserting(_inserting);
|
||||||
_inserting = true;
|
_inserting = true;
|
||||||
|
|
||||||
QTreeWidgetItem *root = topLevelItem(0);
|
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||||
|
|
||||||
if (!root && list.size() <= 1) {
|
if (!root && list.size() <= 1) {
|
||||||
_loading->setText(tr("No subfolders currently on the server."));
|
_loading->setText(tr("No subfolders currently on the server."));
|
||||||
@@ -149,7 +172,7 @@ void SelectiveSyncTreeView::slotUpdateDirectories(const QStringList&list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
root = new QTreeWidgetItem(this);
|
root = new SelectiveSyncTreeViewItem(this);
|
||||||
root->setText(0, _rootName);
|
root->setText(0, _rootName);
|
||||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||||
root->setData(0, Qt::UserRole, QString());
|
root->setData(0, Qt::UserRole, QString());
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "folder.h"
|
#include "folder.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "syncresult.h"
|
#include "syncresult.h"
|
||||||
|
#include "configfile.h"
|
||||||
|
|
||||||
#include "QProgressIndicator.h"
|
#include "QProgressIndicator.h"
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
@@ -44,6 +45,8 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
|||||||
_resharingAllowed(resharingAllowed)
|
_resharingAllowed(resharingAllowed)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setObjectName("SharingDialog"); // required as group for saveGeometry call
|
||||||
|
|
||||||
_ui->setupUi(this);
|
_ui->setupUi(this);
|
||||||
_ui->pushButton_copy->setIcon(QIcon::fromTheme("edit-copy"));
|
_ui->pushButton_copy->setIcon(QIcon::fromTheme("edit-copy"));
|
||||||
_ui->pushButton_copy->setEnabled(false);
|
_ui->pushButton_copy->setEnabled(false);
|
||||||
@@ -84,24 +87,31 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
|||||||
QIcon icon = icon_provider.icon(f_info);
|
QIcon icon = icon_provider.icon(f_info);
|
||||||
_ui->label_icon->setPixmap(icon.pixmap(40,40));
|
_ui->label_icon->setPixmap(icon.pixmap(40,40));
|
||||||
|
|
||||||
QString name;
|
QFileInfo lPath(_localPath);
|
||||||
if( f_info.isDir() ) {
|
QString fileName = lPath.fileName();
|
||||||
name = tr("Share Directory");
|
_ui->label_name->setText(tr("%1").arg(fileName));
|
||||||
} else {
|
QFont f( _ui->label_name->font());
|
||||||
name = tr("Share File");
|
f.setPointSize( f.pointSize() * 1.4 );
|
||||||
}
|
_ui->label_name->setFont( f );
|
||||||
_ui->groupBox->setTitle(name);
|
|
||||||
|
|
||||||
QString lPath(_localPath);
|
|
||||||
if( lPath.length() > 50) {
|
|
||||||
lPath = QLatin1String("...")+lPath.right(50);
|
|
||||||
}
|
|
||||||
_ui->label_name->setText(tr("Local path: %1").arg(lPath));
|
|
||||||
|
|
||||||
_ui->label_sharePath->setWordWrap(true);
|
_ui->label_sharePath->setWordWrap(true);
|
||||||
_ui->label_sharePath->setText(tr("%1 path: %2").arg(Theme::instance()->appNameGUI()).arg(_sharePath));
|
QString ocDir(_sharePath);
|
||||||
|
ocDir.truncate(ocDir.length()-fileName.length());
|
||||||
|
|
||||||
|
if( ocDir == QLatin1String("/")) {
|
||||||
|
_ui->label_sharePath->setText(QString());
|
||||||
|
} else {
|
||||||
|
if( ocDir.startsWith(QLatin1Char('/')) ) {
|
||||||
|
ocDir = ocDir.mid(1, -1);
|
||||||
|
}
|
||||||
|
if( ocDir.endsWith(QLatin1Char('/')) ) {
|
||||||
|
ocDir.chop(1);
|
||||||
|
}
|
||||||
|
_ui->label_sharePath->setText(tr("Folder: %2").arg(ocDir));
|
||||||
|
}
|
||||||
|
|
||||||
this->setWindowTitle(tr("%1 Sharing").arg(Theme::instance()->appNameGUI()));
|
this->setWindowTitle(tr("%1 Sharing").arg(Theme::instance()->appNameGUI()));
|
||||||
_ui->label_password->setText(tr("Set p&assword"));
|
_ui->checkBox_password->setText(tr("P&assword protect"));
|
||||||
// check if the file is already inside of a synced folder
|
// check if the file is already inside of a synced folder
|
||||||
if( sharePath.isEmpty() ) {
|
if( sharePath.isEmpty() ) {
|
||||||
// The file is not yet in an ownCloud synced folder. We could automatically
|
// The file is not yet in an ownCloud synced folder. We could automatically
|
||||||
@@ -128,6 +138,12 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
|||||||
_ui->errorLabel->hide();
|
_ui->errorLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareDialog::done( int r ) {
|
||||||
|
ConfigFile cfg;
|
||||||
|
cfg.saveGeometry(this);
|
||||||
|
QDialog::done(r);
|
||||||
|
}
|
||||||
|
|
||||||
void ShareDialog::setExpireDate(const QDate &date)
|
void ShareDialog::setExpireDate(const QDate &date)
|
||||||
{
|
{
|
||||||
if( _public_share_id == 0 ) {
|
if( _public_share_id == 0 ) {
|
||||||
@@ -331,19 +347,40 @@ void ShareDialog::slotSharesFetched(const QString &reply)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareDialog::resizeEvent(QResizeEvent *e)
|
||||||
|
{
|
||||||
|
QDialog::resizeEvent(e);
|
||||||
|
redrawElidedUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareDialog::redrawElidedUrl()
|
||||||
|
{
|
||||||
|
QString u;
|
||||||
|
|
||||||
|
if( !_shareUrl.isEmpty() ) {
|
||||||
|
QFontMetrics fm( _ui->_labelShareLink->font() );
|
||||||
|
int linkLengthPixel = _ui->_labelShareLink->width();
|
||||||
|
|
||||||
|
const QUrl realUrl(_shareUrl);
|
||||||
|
QString elidedUrl = fm.elidedText(_shareUrl, Qt::ElideRight, linkLengthPixel);
|
||||||
|
|
||||||
|
u = QString("<a href=\"%1\">%2</a>").arg(realUrl.toString(QUrl::None)).arg(elidedUrl);
|
||||||
|
}
|
||||||
|
_ui->_labelShareLink->setText(u);
|
||||||
|
}
|
||||||
|
|
||||||
void ShareDialog::setShareLink( const QString& url )
|
void ShareDialog::setShareLink( const QString& url )
|
||||||
{
|
{
|
||||||
// FIXME: shorten the url for output.
|
// FIXME: shorten the url for output.
|
||||||
const QUrl realUrl(url);
|
const QUrl realUrl(url);
|
||||||
if( realUrl.isValid() ) {
|
if( realUrl.isValid() ) {
|
||||||
const QString u = QString("<a href=\"%1\">%2</a>").arg(realUrl.toString(QUrl::None)).arg(url);
|
|
||||||
_ui->_labelShareLink->setText(u);
|
|
||||||
_shareUrl = url;
|
_shareUrl = url;
|
||||||
_ui->pushButton_copy->setEnabled(true);
|
_ui->pushButton_copy->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
_shareUrl.clear();
|
_shareUrl.clear();
|
||||||
_ui->_labelShareLink->setText(QString::null);
|
_ui->_labelShareLink->setText(QString::null);
|
||||||
}
|
}
|
||||||
|
redrawElidedUrl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +444,7 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
|
|||||||
// there needs to be a password
|
// there needs to be a password
|
||||||
_ui->checkBox_password->setChecked(true);
|
_ui->checkBox_password->setChecked(true);
|
||||||
_ui->checkBox_password->setVisible(false);
|
_ui->checkBox_password->setVisible(false);
|
||||||
_ui->label_password->setText(tr("Public shå requires a password:"));
|
_ui->checkBox_password->setText(tr("Public shå requires a password:"));
|
||||||
_ui->lineEdit_password->setFocus();
|
_ui->lineEdit_password->setFocus();
|
||||||
_ui->widget_shareLink->show();
|
_ui->widget_shareLink->show();
|
||||||
|
|
||||||
@@ -421,13 +458,7 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
|
|||||||
bool success;
|
bool success;
|
||||||
QVariantMap json = QtJson::parse(reply, success).toMap();
|
QVariantMap json = QtJson::parse(reply, success).toMap();
|
||||||
_public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
|
_public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
|
||||||
QString url = json.value("ocs").toMap().values("data")[0].toMap().value("url").toString();
|
getShares();
|
||||||
|
|
||||||
setShareLink(url);
|
|
||||||
|
|
||||||
setShareCheckBoxTitle(true);
|
|
||||||
|
|
||||||
_ui->widget_shareLink->show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotCheckBoxPasswordClicked()
|
void ShareDialog::slotCheckBoxPasswordClicked()
|
||||||
@@ -487,8 +518,8 @@ int ShareDialog::checkJsonReturnCode(const QString &reply, QString &message)
|
|||||||
|
|
||||||
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
||||||
{
|
{
|
||||||
const QString noSharesTitle(tr("Check to &share by public link"));
|
const QString noSharesTitle(tr("&Share link"));
|
||||||
const QString haveSharesTitle(tr("&Shared by public link (uncheck to delete share)"));
|
const QString haveSharesTitle(tr("&Share link"));
|
||||||
|
|
||||||
if( haveShares ) {
|
if( haveShares ) {
|
||||||
_ui->checkBox_shareLink->setText( haveSharesTitle );
|
_ui->checkBox_shareLink->setText( haveSharesTitle );
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class ShareDialog;
|
|||||||
|
|
||||||
class AbstractCredentials;
|
class AbstractCredentials;
|
||||||
class QuotaInfo;
|
class QuotaInfo;
|
||||||
class MirallAccessManager;
|
|
||||||
class SyncResult;
|
class SyncResult;
|
||||||
|
|
||||||
class ShareDialog : public QDialog
|
class ShareDialog : public QDialog
|
||||||
@@ -76,11 +75,15 @@ private slots:
|
|||||||
void slotPasswordChanged(const QString& newText);
|
void slotPasswordChanged(const QString& newText);
|
||||||
void slotPushButtonCopyLinkPressed();
|
void slotPushButtonCopyLinkPressed();
|
||||||
void slotThumbnailFetched(const int &statusCode, const QByteArray &reply);
|
void slotThumbnailFetched(const int &statusCode, const QByteArray &reply);
|
||||||
|
|
||||||
|
void done( int r );
|
||||||
private:
|
private:
|
||||||
void setShareCheckBoxTitle(bool haveShares);
|
void setShareCheckBoxTitle(bool haveShares);
|
||||||
void displayError(int code);
|
void displayError(int code);
|
||||||
void displayError(const QString& errMsg);
|
void displayError(const QString& errMsg);
|
||||||
void setShareLink( const QString& url );
|
void setShareLink( const QString& url );
|
||||||
|
void resizeEvent(QResizeEvent *e);
|
||||||
|
void redrawElidedUrl();
|
||||||
|
|
||||||
Ui::ShareDialog *_ui;
|
Ui::ShareDialog *_ui;
|
||||||
AccountPtr _account;
|
AccountPtr _account;
|
||||||
|
|||||||
@@ -6,23 +6,71 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>403</width>
|
<width>372</width>
|
||||||
<height>296</height>
|
<height>241</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Share NewDocument.odt</string>
|
<string>Share NewDocument.odt</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<item row="4" column="0">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="errorLabel">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<property name="text">
|
<item row="0" column="0" rowspan="2">
|
||||||
<string>TextLabel</string>
|
<widget class="QLabel" name="label_icon">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_name">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>share label</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2" rowspan="2">
|
||||||
|
<widget class="QProgressIndicator" name="pi_share" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="label_sharePath">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ownCloud Path:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_shareLink">
|
<layout class="QHBoxLayout" name="horizontalLayout_shareLink">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_shareLink">
|
<widget class="QCheckBox" name="checkBox_shareLink">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -34,8 +82,14 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="widget_shareLink" native="true">
|
<widget class="QWidget" name="widget_shareLink" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
<property name="topMargin">
|
<property name="topMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@@ -68,7 +122,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_copy">
|
<widget class="QPushButton" name="pushButton_copy">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Copy &Link</string>
|
<string>Copy &link</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -79,30 +133,36 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_password">
|
<widget class="QCheckBox" name="checkBox_password">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>Set password</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_password">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="text">
|
<property name="orientation">
|
||||||
<string>Set p&assword</string>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="sizeHint" stdset="0">
|
||||||
<cstring>checkBox_password</cstring>
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="lineEdit_password">
|
<widget class="QLineEdit" name="lineEdit_password">
|
||||||
<property name="echoMode">
|
<property name="echoMode">
|
||||||
@@ -112,15 +172,24 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_setPassword">
|
<widget class="QPushButton" name="pushButton_setPassword">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Set &Password</string>
|
<string>Set &password </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_expire">
|
<widget class="QCheckBox" name="checkBox_expire">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -140,80 +209,6 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Close</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
|
||||||
<string>Share Info</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0" rowspan="2">
|
|
||||||
<widget class="QLabel" name="label_icon">
|
|
||||||
<property name="text">
|
|
||||||
<string>TextLabel</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label_name">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>share label</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2" rowspan="2">
|
|
||||||
<widget class="QProgressIndicator" name="pi_share" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLabel" name="label_sharePath">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>50</weight>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>ownCloud Path:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -227,7 +222,37 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="errorLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
<zorder>errorLabel</zorder>
|
||||||
|
<zorder>widget_shareLink</zorder>
|
||||||
|
<zorder>buttonBox</zorder>
|
||||||
|
<zorder>checkBox_password</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de>
|
* Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de>
|
||||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
* Copyright (C) by Roeland Jago Douma <roeland@famdouma.nl>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
#include "syncfileitem.h"
|
#include "syncfileitem.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "accountstate.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
@@ -136,7 +138,9 @@ SocketApi::~SocketApi()
|
|||||||
{
|
{
|
||||||
DEBUG << "dtor";
|
DEBUG << "dtor";
|
||||||
_localServer.close();
|
_localServer.close();
|
||||||
qDeleteAll(_listeners);
|
// All remaining sockets will be destroyed with _localServer, their parent
|
||||||
|
Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
|
||||||
|
_listeners.clear();
|
||||||
slotClearExcludesList();
|
slotClearExcludesList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +167,7 @@ void SocketApi::slotReadExcludes()
|
|||||||
|
|
||||||
void SocketApi::slotNewConnection()
|
void SocketApi::slotNewConnection()
|
||||||
{
|
{
|
||||||
SocketType* socket = _localServer.nextPendingConnection();
|
QLocalSocket* socket = _localServer.nextPendingConnection();
|
||||||
|
|
||||||
if( ! socket ) {
|
if( ! socket ) {
|
||||||
return;
|
return;
|
||||||
@@ -195,7 +199,7 @@ void SocketApi::onLostConnection()
|
|||||||
{
|
{
|
||||||
DEBUG << "Lost connection " << sender();
|
DEBUG << "Lost connection " << sender();
|
||||||
|
|
||||||
SocketType* socket = qobject_cast<SocketType*>(sender());
|
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
|
||||||
_listeners.removeAll(socket);
|
_listeners.removeAll(socket);
|
||||||
socket->deleteLater();
|
socket->deleteLater();
|
||||||
}
|
}
|
||||||
@@ -203,7 +207,7 @@ void SocketApi::onLostConnection()
|
|||||||
|
|
||||||
void SocketApi::slotReadSocket()
|
void SocketApi::slotReadSocket()
|
||||||
{
|
{
|
||||||
SocketType* socket = qobject_cast<SocketType*>(sender());
|
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
|
||||||
Q_ASSERT(socket);
|
Q_ASSERT(socket);
|
||||||
|
|
||||||
while(socket->canReadLine()) {
|
while(socket->canReadLine()) {
|
||||||
@@ -211,12 +215,12 @@ void SocketApi::slotReadSocket()
|
|||||||
QString command = line.split(":").first();
|
QString command = line.split(":").first();
|
||||||
QString function = QString(QLatin1String("command_")).append(command);
|
QString function = QString(QLatin1String("command_")).append(command);
|
||||||
|
|
||||||
QString functionWithArguments = function + QLatin1String("(QString,SocketType*)");
|
QString functionWithArguments = function + QLatin1String("(QString,QLocalSocket*)");
|
||||||
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
||||||
|
|
||||||
QString argument = line.remove(0, command.length()+1).trimmed();
|
QString argument = line.remove(0, command.length()+1).trimmed();
|
||||||
if(indexOfMethod != -1) {
|
if(indexOfMethod != -1) {
|
||||||
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(SocketType*, socket));
|
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QLocalSocket*, socket));
|
||||||
} else {
|
} else {
|
||||||
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
||||||
}
|
}
|
||||||
@@ -228,7 +232,7 @@ void SocketApi::slotRegisterPath( const QString& alias )
|
|||||||
Folder *f = FolderMan::instance()->folder(alias);
|
Folder *f = FolderMan::instance()->folder(alias);
|
||||||
if (f) {
|
if (f) {
|
||||||
QString message = buildRegisterPathMessage(f->path());
|
QString message = buildRegisterPathMessage(f->path());
|
||||||
foreach(SocketType *socket, _listeners) {
|
foreach(QLocalSocket *socket, _listeners) {
|
||||||
sendMessage(socket, message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,7 +337,7 @@ void SocketApi::slotSyncItemDiscovered(const QString &folder, const SyncFileItem
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SocketApi::sendMessage(SocketType *socket, const QString& message, bool doWait)
|
void SocketApi::sendMessage(QLocalSocket *socket, const QString& message, bool doWait)
|
||||||
{
|
{
|
||||||
DEBUG << "Sending message: " << message;
|
DEBUG << "Sending message: " << message;
|
||||||
QString localMessage = message;
|
QString localMessage = message;
|
||||||
@@ -368,12 +372,12 @@ void SocketApi::broadcastMessage( const QString& verb, const QString& path, cons
|
|||||||
|
|
||||||
// sendMessage already has a debug output
|
// sendMessage already has a debug output
|
||||||
//DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << msg;
|
//DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << msg;
|
||||||
foreach(SocketType *socket, _listeners) {
|
foreach(QLocalSocket *socket, _listeners) {
|
||||||
sendMessage(socket, msg, doWait);
|
sendMessage(socket, msg, doWait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketType* socket)
|
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket)
|
||||||
{
|
{
|
||||||
// This command is the same as RETRIEVE_FILE_STATUS
|
// This command is the same as RETRIEVE_FILE_STATUS
|
||||||
|
|
||||||
@@ -381,7 +385,7 @@ void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketTy
|
|||||||
command_RETRIEVE_FILE_STATUS(argument, socket);
|
command_RETRIEVE_FILE_STATUS(argument, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType* socket)
|
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QLocalSocket* socket)
|
||||||
{
|
{
|
||||||
if( !socket ) {
|
if( !socket ) {
|
||||||
qDebug() << "No valid socket object.";
|
qDebug() << "No valid socket object.";
|
||||||
@@ -409,7 +413,7 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType
|
|||||||
sendMessage(socket, message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
void SocketApi::command_SHARE(const QString& localFile, QLocalSocket* socket)
|
||||||
{
|
{
|
||||||
if (!socket) {
|
if (!socket) {
|
||||||
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||||
@@ -423,6 +427,10 @@ void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
|||||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||||
// files that are not within a sync folder are not synced.
|
// files that are not within a sync folder are not synced.
|
||||||
sendMessage(socket, message);
|
sendMessage(socket, message);
|
||||||
|
} else if (!shareFolder->accountState()->isConnected()) {
|
||||||
|
const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
|
||||||
|
// if the folder isn't connected, don't open the share dialog
|
||||||
|
sendMessage(socket, message);
|
||||||
} else {
|
} else {
|
||||||
const QString folderForPath = shareFolder->path();
|
const QString folderForPath = shareFolder->path();
|
||||||
const QString remotePath = shareFolder->remotePath() + localFile.right(localFile.count()-folderForPath.count()+1);
|
const QString remotePath = shareFolder->remotePath() + localFile.right(localFile.count()-folderForPath.count()+1);
|
||||||
@@ -443,12 +451,12 @@ void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_VERSION(const QString&, SocketType* socket)
|
void SocketApi::command_VERSION(const QString&, QLocalSocket* socket)
|
||||||
{
|
{
|
||||||
sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketType* socket)
|
void SocketApi::command_SHARE_MENU_TITLE(const QString &, QLocalSocket* socket)
|
||||||
{
|
{
|
||||||
sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ class QStringList;
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
typedef QLocalSocket SocketType;
|
|
||||||
|
|
||||||
class SyncFileStatus;
|
class SyncFileStatus;
|
||||||
class Folder;
|
class Folder;
|
||||||
|
|
||||||
@@ -72,24 +70,20 @@ private:
|
|||||||
SyncJournalFileRecord dbFileRecord_capi( Folder *folder, QString fileName );
|
SyncJournalFileRecord dbFileRecord_capi( Folder *folder, QString fileName );
|
||||||
SqlQuery *getSqlQuery( Folder *folder );
|
SqlQuery *getSqlQuery( Folder *folder );
|
||||||
|
|
||||||
void sendMessage(SocketType* socket, const QString& message, bool doWait = false);
|
void sendMessage(QLocalSocket* socket, const QString& message, bool doWait = false);
|
||||||
void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
|
void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
|
||||||
|
|
||||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketType* socket);
|
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket);
|
||||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType* socket);
|
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QLocalSocket* socket);
|
||||||
Q_INVOKABLE void command_SHARE(const QString& localFile, SocketType* socket);
|
Q_INVOKABLE void command_SHARE(const QString& localFile, QLocalSocket* socket);
|
||||||
|
|
||||||
Q_INVOKABLE void command_VERSION(const QString& argument, SocketType* socket);
|
Q_INVOKABLE void command_VERSION(const QString& argument, QLocalSocket* socket);
|
||||||
|
|
||||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, SocketType* socket);
|
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QLocalSocket* socket);
|
||||||
QString buildRegisterPathMessage(const QString& path);
|
QString buildRegisterPathMessage(const QString& path);
|
||||||
|
|
||||||
#ifdef SOCKETAPI_TCP
|
QList<QLocalSocket*> _listeners;
|
||||||
QTcpServer _localServer;
|
|
||||||
#else
|
|
||||||
QLocalServer _localServer;
|
QLocalServer _localServer;
|
||||||
#endif
|
|
||||||
QList<SocketType*> _listeners;
|
|
||||||
c_strlist_t *_excludes;
|
c_strlist_t *_excludes;
|
||||||
QHash<Folder*, SqlQuery*> _dbQueries;
|
QHash<Folder*, SqlQuery*> _dbQueries;
|
||||||
QHash<Folder*, SqlDatabase*> _openDbs;
|
QHash<Folder*, SqlDatabase*> _openDbs;
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ SslButton::SslButton(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
setPopupMode(QToolButton::InstantPopup);
|
setPopupMode(QToolButton::InstantPopup);
|
||||||
setAutoRaise(true);
|
setAutoRaise(true);
|
||||||
|
|
||||||
|
setMenu(new QMenu(this));
|
||||||
|
QObject::connect(menu(), SIGNAL(aboutToShow()),
|
||||||
|
this, SLOT(slotUpdateMenu()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SslButton::protoToString(QSsl::SslProtocol proto)
|
QString SslButton::protoToString(QSsl::SslProtocol proto)
|
||||||
@@ -178,19 +182,39 @@ void SslButton::updateAccountState(AccountState *accountState)
|
|||||||
} else {
|
} else {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
AccountPtr account = accountState->account();
|
_accountState = accountState;
|
||||||
if(QMenu *oldMenu = menu()) {
|
|
||||||
oldMenu->hide(); // Need to be hidden because the QToolButton would be left in invalid state if the menu is deleted while it is visible
|
AccountPtr account = _accountState->account();
|
||||||
setMenu(0);
|
|
||||||
oldMenu->deleteLater(); // setMenu do not delete the previous menu.
|
|
||||||
}
|
|
||||||
if (account->url().scheme() == QLatin1String("https")) {
|
if (account->url().scheme() == QLatin1String("https")) {
|
||||||
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-https.png"))));
|
QPixmap pm(Theme::hidpiFileName(":/client/resources/lock-https.png"));
|
||||||
|
setIcon(QIcon(pm));
|
||||||
QSslCipher cipher = account->sslConfiguration().sessionCipher();
|
QSslCipher cipher = account->sslConfiguration().sessionCipher();
|
||||||
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
||||||
QMenu *menu = new QMenu(this);
|
} else {
|
||||||
|
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png"))));
|
||||||
|
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SslButton::slotUpdateMenu() {
|
||||||
|
menu()->clear();
|
||||||
|
|
||||||
|
if (!_accountState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountPtr account = _accountState->account();
|
||||||
|
|
||||||
|
if (account->url().scheme() == QLatin1String("https")) {
|
||||||
|
|
||||||
QList<QSslCertificate> chain = account->sslConfiguration().peerCertificateChain();
|
QList<QSslCertificate> chain = account->sslConfiguration().peerCertificateChain();
|
||||||
menu->addAction(tr("Certificate information:"))->setEnabled(false);
|
|
||||||
|
if (chain.isEmpty()) {
|
||||||
|
qWarning() << "empty certificate chain";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu()->addAction(tr("Certificate information:"))->setEnabled(false);
|
||||||
|
|
||||||
QList<QSslCertificate> tmpChain;
|
QList<QSslCertificate> tmpChain;
|
||||||
foreach(QSslCertificate cert, chain) {
|
foreach(QSslCertificate cert, chain) {
|
||||||
@@ -213,13 +237,9 @@ void SslButton::updateAccountState(AccountState *accountState)
|
|||||||
it.toBack();
|
it.toBack();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (it.hasPrevious()) {
|
while (it.hasPrevious()) {
|
||||||
menu->addMenu(buildCertMenu(menu, it.previous(), account->approvedCerts(), i));
|
menu()->addMenu(buildCertMenu(menu(), it.previous(), account->approvedCerts(), i));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
setMenu(menu);
|
|
||||||
} else {
|
|
||||||
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png"))));
|
|
||||||
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ class QSslConfiguration;
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class Account;
|
|
||||||
class AccountState;
|
class AccountState;
|
||||||
|
|
||||||
class SslButton : public QToolButton
|
class SslButton : public QToolButton
|
||||||
@@ -35,9 +34,13 @@ public:
|
|||||||
QString protoToString(QSsl::SslProtocol proto);
|
QString protoToString(QSsl::SslProtocol proto);
|
||||||
void updateAccountState(AccountState *accountState);
|
void updateAccountState(AccountState *accountState);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotUpdateMenu();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMenu* buildCertMenu(QMenu *parent, const QSslCertificate& cert,
|
QMenu* buildCertMenu(QMenu *parent, const QSslCertificate& cert,
|
||||||
const QList<QSslCertificate>& userApproved, int pos);
|
const QList<QSslCertificate>& userApproved, int pos);
|
||||||
|
QPointer<AccountState> _accountState;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ namespace Utility {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool SslDialogErrorHandler::handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, AccountPtr account)
|
bool SslDialogErrorHandler::handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, AccountPtr account)
|
||||||
{
|
{
|
||||||
|
(void) conf;
|
||||||
if (!certs) {
|
if (!certs) {
|
||||||
qDebug() << "Certs parameter required but is NULL!";
|
qDebug() << "Certs parameter required but is NULL!";
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class SslErrorDialog;
|
|||||||
|
|
||||||
class SslDialogErrorHandler : public AbstractSslErrorHandler {
|
class SslDialogErrorHandler : public AbstractSslErrorHandler {
|
||||||
public:
|
public:
|
||||||
bool handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, AccountPtr) Q_DECL_OVERRIDE;
|
bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, AccountPtr) Q_DECL_OVERRIDE;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SslErrorDialog : public QDialog
|
class SslErrorDialog : public QDialog
|
||||||
|
|||||||
@@ -52,9 +52,10 @@ bool OCUpdater::performUpdate()
|
|||||||
QSettings settings(cfg.configFile(), QSettings::IniFormat);
|
QSettings settings(cfg.configFile(), QSettings::IniFormat);
|
||||||
QString updateFile = settings.value(updateAvailableC).toString();
|
QString updateFile = settings.value(updateAvailableC).toString();
|
||||||
if (!updateFile.isEmpty() && QFile(updateFile).exists()) {
|
if (!updateFile.isEmpty() && QFile(updateFile).exists()) {
|
||||||
if (QMessageBox::information(0, tr("New Update Ready"),
|
const QString name = Theme::instance()->appNameGUI();
|
||||||
tr("A new update is about to be installed. The updater may ask\n"
|
if (QMessageBox::information(0, tr("New %1 Update Ready").arg(name),
|
||||||
"for additional privileges during the process."), QMessageBox::Ok)) {
|
tr("A new update for %1 is about to be installed. The updater may ask\n"
|
||||||
|
"for additional privileges during the process.").arg(name), QMessageBox::Ok)) {
|
||||||
slotStartInstaller();
|
slotStartInstaller();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/gui/version.rc.in
Normal file
25
src/gui/version.rc.in
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "winresrc.h"
|
||||||
|
|
||||||
|
#define VER_FILEVERSION @MIRALL_VERSION_MAJOR@,@MIRALL_VERSION_MINOR@,@MIRALL_VERSION_PATCH@,@MIRALL_VERSION_BUILD@
|
||||||
|
#define VER_FILEVERSION_STR "@MIRALL_VERSION_MAJOR@.@MIRALL_VERSION_MINOR@.@MIRALL_VERSION_PATCH@.@MIRALL_VERSION_BUILD@\0"
|
||||||
|
|
||||||
|
#define VER_PRODUCTVERSION @MIRALL_VERSION_MAJOR@,@MIRALL_VERSION_MINOR@,@MIRALL_VERSION_PATCH@,@MIRALL_VERSION_BUILD@
|
||||||
|
#define VER_PRODUCTVERSION_STR "@MIRALL_VERSION_MAJOR@.@MIRALL_VERSION_MINOR@.@MIRALL_VERSION_PATCH@.@MIRALL_VERSION_BUILD@\0"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION VER_FILEVERSION
|
||||||
|
PRODUCTVERSION VER_PRODUCTVERSION
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "080904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||||
|
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x809, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
@@ -64,7 +64,6 @@ set(libsync_SRCS
|
|||||||
creds/dummycredentials.cpp
|
creds/dummycredentials.cpp
|
||||||
creds/abstractcredentials.cpp
|
creds/abstractcredentials.cpp
|
||||||
creds/credentialsfactory.cpp
|
creds/credentialsfactory.cpp
|
||||||
creds/http/httpconfigfile.cpp
|
|
||||||
creds/credentialscommon.cpp
|
creds/credentialscommon.cpp
|
||||||
../3rdparty/qjson/json.cpp
|
../3rdparty/qjson/json.cpp
|
||||||
../3rdparty/certificates/p12topem.cpp
|
../3rdparty/certificates/p12topem.cpp
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ void AccountManager::setAccount(AccountPtr account)
|
|||||||
emit accountRemoved(_account);
|
emit accountRemoved(_account);
|
||||||
}
|
}
|
||||||
_account = account;
|
_account = account;
|
||||||
emit accountAdded(account);
|
if (account) {
|
||||||
|
emit accountAdded(account);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -129,6 +131,15 @@ void Account::save()
|
|||||||
if (!certs.isEmpty()) {
|
if (!certs.isEmpty()) {
|
||||||
settings->setValue( QLatin1String(caCertsKeyC), certs );
|
settings->setValue( QLatin1String(caCertsKeyC), certs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save cookies.
|
||||||
|
if (_am) {
|
||||||
|
CookieJar* jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
||||||
|
if (jar) {
|
||||||
|
qDebug() << "Saving cookies.";
|
||||||
|
jar->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountPtr Account::restore()
|
AccountPtr Account::restore()
|
||||||
@@ -271,6 +282,21 @@ void Account::clearCookieJar()
|
|||||||
_am->setCookieJar(new CookieJar);
|
_am->setCookieJar(new CookieJar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Account::resetNetworkAccessManager()
|
||||||
|
{
|
||||||
|
if (!_credentials || !_am) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Resetting QNAM";
|
||||||
|
QNetworkCookieJar* jar = _am->cookieJar();
|
||||||
|
_am->deleteLater();
|
||||||
|
_am = _credentials->getQNAM();
|
||||||
|
_am->setCookieJar(jar); // takes ownership of the old cookie jar
|
||||||
|
connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
|
||||||
|
SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkAccessManager *Account::networkAccessManager()
|
QNetworkAccessManager *Account::networkAccessManager()
|
||||||
{
|
{
|
||||||
return _am;
|
return _am;
|
||||||
@@ -295,7 +321,9 @@ QNetworkReply *Account::getRequest(const QString &relPath)
|
|||||||
QNetworkReply *Account::getRequest(const QUrl &url)
|
QNetworkReply *Account::getRequest(const QUrl &url)
|
||||||
{
|
{
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
request.setSslConfiguration(this->createSslConfig());
|
request.setSslConfiguration(this->createSslConfig());
|
||||||
|
#endif
|
||||||
return _am->get(request);
|
return _am->get(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +335,9 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QString &relPat
|
|||||||
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
||||||
{
|
{
|
||||||
req.setUrl(url);
|
req.setUrl(url);
|
||||||
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
req.setSslConfiguration(this->createSslConfig());
|
req.setSslConfiguration(this->createSslConfig());
|
||||||
|
#endif
|
||||||
return _am->sendCustomRequest(req, verb, data);
|
return _am->sendCustomRequest(req, verb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +490,7 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_sslErrorHandler->handleErrors(errors, &approvedCerts, sharedFromThis())) {
|
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
|
||||||
QSslSocket::addDefaultCaCertificates(approvedCerts);
|
QSslSocket::addDefaultCaCertificates(approvedCerts);
|
||||||
addApprovedCerts(approvedCerts);
|
addApprovedCerts(approvedCerts);
|
||||||
// all ssl certs are known and accepted. We can ignore the problems right away.
|
// all ssl certs are known and accepted. We can ignore the problems right away.
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
class AbstractSslErrorHandler {
|
class AbstractSslErrorHandler {
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractSslErrorHandler() {}
|
virtual ~AbstractSslErrorHandler() {}
|
||||||
virtual bool handleErrors(QList<QSslError>, QList<QSslCertificate>*, AccountPtr) = 0;
|
virtual bool handleErrors(QList<QSslError>, const QSslConfiguration &conf, QList<QSslCertificate>*, AccountPtr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +156,7 @@ public:
|
|||||||
|
|
||||||
void clearCookieJar();
|
void clearCookieJar();
|
||||||
|
|
||||||
|
void resetNetworkAccessManager();
|
||||||
QNetworkAccessManager* networkAccessManager();
|
QNetworkAccessManager* networkAccessManager();
|
||||||
|
|
||||||
/// Called by network jobs on credential errors.
|
/// Called by network jobs on credential errors.
|
||||||
@@ -185,7 +186,6 @@ private:
|
|||||||
QNetworkAccessManager *_am;
|
QNetworkAccessManager *_am;
|
||||||
AbstractCredentials* _credentials;
|
AbstractCredentials* _credentials;
|
||||||
bool _treatSslErrorsAsFailure;
|
bool _treatSslErrorsAsFailure;
|
||||||
int _state;
|
|
||||||
static QString _configFileName;
|
static QString _configFileName;
|
||||||
QByteArray _pemCertificate;
|
QByteArray _pemCertificate;
|
||||||
QString _pemPrivateKey;
|
QString _pemPrivateKey;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QThreadPool>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ ClientProxy::ClientProxy(QObject *parent) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkProxy ClientProxy::proxyFromConfig(const ConfigFile& cfg)
|
static QNetworkProxy proxyFromConfig(const ConfigFile& cfg)
|
||||||
{
|
{
|
||||||
QNetworkProxy proxy;
|
QNetworkProxy proxy;
|
||||||
|
|
||||||
@@ -39,6 +40,22 @@ QNetworkProxy ClientProxy::proxyFromConfig(const ConfigFile& cfg)
|
|||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClientProxy::isUsingSystemDefault() {
|
||||||
|
OCC::ConfigFile cfg;
|
||||||
|
|
||||||
|
// if there is no config file, default to system proxy.
|
||||||
|
if( cfg.exists() ) {
|
||||||
|
return cfg.proxyType() == QNetworkProxy::DefaultProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString printQNetworkProxy(const QNetworkProxy &proxy)
|
||||||
|
{
|
||||||
|
return QString("%1://%2:%3").arg(proxy.type()).arg(proxy.hostName()).arg(proxy.port());
|
||||||
|
}
|
||||||
|
|
||||||
void ClientProxy::setupQtProxyFromConfig()
|
void ClientProxy::setupQtProxyFromConfig()
|
||||||
{
|
{
|
||||||
OCC::ConfigFile cfg;
|
OCC::ConfigFile cfg;
|
||||||
@@ -53,19 +70,23 @@ void ClientProxy::setupQtProxyFromConfig()
|
|||||||
|
|
||||||
switch(proxyType) {
|
switch(proxyType) {
|
||||||
case QNetworkProxy::NoProxy:
|
case QNetworkProxy::NoProxy:
|
||||||
|
qDebug() << "Set proxy configuration to use NO proxy";
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||||
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
|
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
|
||||||
break;
|
break;
|
||||||
case QNetworkProxy::DefaultProxy:
|
case QNetworkProxy::DefaultProxy:
|
||||||
|
qDebug() << "Set proxy configuration to use system configuration";
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||||
break;
|
break;
|
||||||
case QNetworkProxy::Socks5Proxy:
|
case QNetworkProxy::Socks5Proxy:
|
||||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||||
|
qDebug() << "Set proxy configuration to SOCKS5" << printQNetworkProxy(proxy);
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||||
QNetworkProxy::setApplicationProxy(proxy);
|
QNetworkProxy::setApplicationProxy(proxy);
|
||||||
break;
|
break;
|
||||||
case QNetworkProxy::HttpProxy:
|
case QNetworkProxy::HttpProxy:
|
||||||
proxy.setType(QNetworkProxy::HttpProxy);
|
proxy.setType(QNetworkProxy::HttpProxy);
|
||||||
|
qDebug() << "Set proxy configuration to HTTP" << printQNetworkProxy(proxy);
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||||
QNetworkProxy::setApplicationProxy(proxy);
|
QNetworkProxy::setApplicationProxy(proxy);
|
||||||
break;
|
break;
|
||||||
@@ -96,6 +117,7 @@ const char* ClientProxy::proxyTypeToCStr(QNetworkProxy::ProxyType type)
|
|||||||
|
|
||||||
void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
|
void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
|
||||||
{
|
{
|
||||||
|
#ifdef USE_NEON
|
||||||
/* Store proxy */
|
/* Store proxy */
|
||||||
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(url));
|
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(url));
|
||||||
// We set at least one in Application
|
// We set at least one in Application
|
||||||
@@ -118,7 +140,39 @@ void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
|
|||||||
csync_set_module_property( csync_ctx, "proxy_port", &proxy_port );
|
csync_set_module_property( csync_ctx, "proxy_port", &proxy_port );
|
||||||
csync_set_module_property( csync_ctx, "proxy_user", proxy.user().toUtf8().data());
|
csync_set_module_property( csync_ctx, "proxy_user", proxy.user().toUtf8().data());
|
||||||
csync_set_module_property( csync_ctx, "proxy_pwd", proxy.password().toUtf8().data());
|
csync_set_module_property( csync_ctx, "proxy_pwd", proxy.password().toUtf8().data());
|
||||||
|
#else
|
||||||
|
Q_UNUSED(url);
|
||||||
|
Q_UNUSED(csync_ctx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ClientProxy::lookupSystemProxyAsync(const QUrl &url, QObject *dst, const char *slot)
|
||||||
|
{
|
||||||
|
SystemProxyRunnable *runnable = new SystemProxyRunnable(url);
|
||||||
|
QObject::connect(runnable, SIGNAL(systemProxyLookedUp(QNetworkProxy)), dst, slot);
|
||||||
|
QThreadPool::globalInstance()->start(runnable); // takes ownership and deletes
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemProxyRunnable::SystemProxyRunnable(const QUrl &url) : QObject(), QRunnable(), _url(url)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemProxyRunnable::run()
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << "Starting system proxy lookup";
|
||||||
|
qRegisterMetaType<QNetworkProxy>("QNetworkProxy");
|
||||||
|
QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(_url));
|
||||||
|
|
||||||
|
if (proxies.isEmpty()) {
|
||||||
|
emit systemProxyLookedUp(QNetworkProxy(QNetworkProxy::NoProxy));
|
||||||
|
} else {
|
||||||
|
emit systemProxyLookedUp(proxies.first());
|
||||||
|
// FIXME Would we really ever return more?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
|
#include <QRunnable>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include <csync.h>
|
#include <csync.h>
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
@@ -30,17 +32,31 @@ class OWNCLOUDSYNC_EXPORT ClientProxy : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit ClientProxy(QObject *parent = 0);
|
explicit ClientProxy(QObject *parent = 0);
|
||||||
|
|
||||||
signals:
|
static bool isUsingSystemDefault();
|
||||||
|
static void lookupSystemProxyAsync(const QUrl &url, QObject *dst, const char *slot);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setCSyncProxy( const QUrl& url, CSYNC *csync_ctx );
|
void setCSyncProxy( const QUrl& url, CSYNC *csync_ctx );
|
||||||
void setupQtProxyFromConfig();
|
void setupQtProxyFromConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkProxy proxyFromConfig(const ConfigFile& cfg);
|
|
||||||
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SystemProxyRunnable : public QObject, public QRunnable {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SystemProxyRunnable(const QUrl &url);
|
||||||
|
void run();
|
||||||
|
signals:
|
||||||
|
void systemProxyLookedUp(const QNetworkProxy &url);
|
||||||
|
private:
|
||||||
|
QUrl _url;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString printQNetworkProxy(const QNetworkProxy &proxy);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CLIENTPROXY_H
|
#endif // CLIENTPROXY_H
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
static const char caCertsKeyC[] = "CaCertificates";
|
//static const char caCertsKeyC[] = "CaCertificates"; only used from account.cpp
|
||||||
static const char remotePollIntervalC[] = "remotePollInterval";
|
static const char remotePollIntervalC[] = "remotePollInterval";
|
||||||
static const char forceSyncIntervalC[] = "forceSyncInterval";
|
static const char forceSyncIntervalC[] = "forceSyncInterval";
|
||||||
static const char monoIconsC[] = "monoIcons";
|
static const char monoIconsC[] = "monoIcons";
|
||||||
@@ -85,10 +85,10 @@ ConfigFile::ConfigFile()
|
|||||||
// qDebug() << Q_FUNC_INFO << "Loading config: " << config << " (URL is " << settings.value("url").toString() << ")";
|
// qDebug() << Q_FUNC_INFO << "Loading config: " << config << " (URL is " << settings.value("url").toString() << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigFile::setConfDir(const QString &value)
|
bool ConfigFile::setConfDir(const QString &value)
|
||||||
{
|
{
|
||||||
QString dirPath = value;
|
QString dirPath = value;
|
||||||
if( dirPath.isEmpty() ) return;
|
if( dirPath.isEmpty() ) return false;
|
||||||
|
|
||||||
QFileInfo fi(dirPath);
|
QFileInfo fi(dirPath);
|
||||||
if ( !fi.exists() && !fi.isAbsolute() ) {
|
if ( !fi.exists() && !fi.isAbsolute() ) {
|
||||||
@@ -101,7 +101,9 @@ void ConfigFile::setConfDir(const QString &value)
|
|||||||
dirPath = fi.absoluteFilePath();
|
dirPath = fi.absoluteFilePath();
|
||||||
qDebug() << "** Using custom config dir " << dirPath;
|
qDebug() << "** Using custom config dir " << dirPath;
|
||||||
_confDir=dirPath;
|
_confDir=dirPath;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigFile::optionalDesktopNotifications() const
|
bool ConfigFile::optionalDesktopNotifications() const
|
||||||
@@ -145,7 +147,7 @@ void ConfigFile::saveGeometryHeader(QHeaderView *header)
|
|||||||
{
|
{
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
if(!header) return;
|
if(!header) return;
|
||||||
Q_ASSERT(!header->objectName().isNull());
|
Q_ASSERT(!header->objectName().isEmpty());
|
||||||
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.beginGroup(header->objectName());
|
settings.beginGroup(header->objectName());
|
||||||
@@ -162,7 +164,7 @@ void ConfigFile::restoreGeometryHeader(QHeaderView *header)
|
|||||||
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.beginGroup(header->objectName());
|
settings.beginGroup(header->objectName());
|
||||||
header->restoreState(getValue(geometryC, header->objectName()).toByteArray());
|
header->restoreState(settings.value(geometryC).toByteArray());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,20 +317,6 @@ bool ConfigFile::dataExists(const QString& group, const QString& key) const
|
|||||||
return settings.contains(key);
|
return settings.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ConfigFile::caCerts( )
|
|
||||||
{
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
|
||||||
return settings.value( QLatin1String(caCertsKeyC) ).toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigFile::setCaCerts( const QByteArray & certs )
|
|
||||||
{
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
|
||||||
|
|
||||||
settings.setValue( QLatin1String(caCertsKeyC), certs );
|
|
||||||
settings.sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigFile::remotePollInterval( const QString& connection ) const
|
int ConfigFile::remotePollInterval( const QString& connection ) const
|
||||||
{
|
{
|
||||||
QString con( connection );
|
QString con( connection );
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public:
|
|||||||
void setUploadLimit(int kbytes);
|
void setUploadLimit(int kbytes);
|
||||||
void setDownloadLimit(int kbytes);
|
void setDownloadLimit(int kbytes);
|
||||||
|
|
||||||
static void setConfDir(const QString &value);
|
static bool setConfDir(const QString &value);
|
||||||
|
|
||||||
bool optionalDesktopNotifications() const;
|
bool optionalDesktopNotifications() const;
|
||||||
void setOptionalDesktopNotifications(bool show);
|
void setOptionalDesktopNotifications(bool show);
|
||||||
|
|||||||
@@ -13,11 +13,13 @@
|
|||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkProxyFactory>
|
||||||
|
|
||||||
#include "connectionvalidator.h"
|
#include "connectionvalidator.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "networkjobs.h"
|
#include "networkjobs.h"
|
||||||
|
#include "clientproxy.h"
|
||||||
#include <creds/abstractcredentials.h>
|
#include <creds/abstractcredentials.h>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
@@ -61,8 +63,38 @@ void ConnectionValidator::checkServerAndAuth()
|
|||||||
reportResult( NotConfigured );
|
reportResult( NotConfigured );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qDebug() << "Checking server and authentication";
|
||||||
|
|
||||||
_isCheckingServerAndAuth = true;
|
_isCheckingServerAndAuth = true;
|
||||||
|
|
||||||
|
// Lookup system proxy in a thread https://github.com/owncloud/client/issues/2993
|
||||||
|
if (ClientProxy::isUsingSystemDefault()) {
|
||||||
|
qDebug() << "Trying to look up system proxy";
|
||||||
|
ClientProxy::lookupSystemProxyAsync(_account->url(),
|
||||||
|
this, SLOT(systemProxyLookupDone(QNetworkProxy)));
|
||||||
|
} else {
|
||||||
|
// We want to reset the QNAM proxy so that the global proxy settings are used (via ClientProxy settings)
|
||||||
|
_account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||||
|
// use a queued invocation so we're as asynchronous as with the other code path
|
||||||
|
QMetaObject::invokeMethod(this, "slotCheckServerAndAuth", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionValidator::systemProxyLookupDone(const QNetworkProxy &proxy) {
|
||||||
|
if (!_account) {
|
||||||
|
qDebug() << "Bailing out, Account had been deleted";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << Q_FUNC_INFO << "Setting QNAM proxy to be system proxy" << printQNetworkProxy(proxy);
|
||||||
|
_account->networkAccessManager()->setProxy(proxy);
|
||||||
|
|
||||||
|
slotCheckServerAndAuth();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The actual check
|
||||||
|
void ConnectionValidator::slotCheckServerAndAuth()
|
||||||
|
{
|
||||||
CheckServerJob *checkJob = new CheckServerJob(_account, this);
|
CheckServerJob *checkJob = new CheckServerJob(_account, this);
|
||||||
checkJob->setIgnoreCredentialFailure(true);
|
checkJob->setIgnoreCredentialFailure(true);
|
||||||
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
|
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
|
||||||
@@ -98,12 +130,16 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
|
|||||||
// Fetch them now! Once fetched, a new connectivity check will be
|
// Fetch them now! Once fetched, a new connectivity check will be
|
||||||
// initiated anyway.
|
// initiated anyway.
|
||||||
creds->fetch();
|
creds->fetch();
|
||||||
|
|
||||||
|
// no result is reported
|
||||||
|
deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// status.php could not be loaded (network or server issue!).
|
// status.php could not be loaded (network or server issue!).
|
||||||
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
|
||||||
if( reply && ! _account->credentials()->stillValid(reply)) {
|
if( reply && ! _account->credentials()->stillValid(reply)) {
|
||||||
_errors.append(tr("Authentication error: Either username or password are wrong."));
|
_errors.append(tr("Authentication error: Either username or password are wrong."));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ namespace OCC {
|
|||||||
|
|
||||||
|
|
||||||
*---> checkServerAndAuth (check status.php)
|
*---> checkServerAndAuth (check status.php)
|
||||||
|
Will asynchronously check for system proxy (if using system proxy)
|
||||||
|
And then invoke slotCheckServerAndAuth
|
||||||
CheckServerJob
|
CheckServerJob
|
||||||
|
|
|
|
||||||
+-> slotNoStatusFound --> X
|
+-> slotNoStatusFound --> X
|
||||||
@@ -85,6 +87,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
/// Checks the server and the authentication.
|
/// Checks the server and the authentication.
|
||||||
void checkServerAndAuth();
|
void checkServerAndAuth();
|
||||||
|
void systemProxyLookupDone(const QNetworkProxy &proxy);
|
||||||
|
|
||||||
/// Checks authentication only.
|
/// Checks authentication only.
|
||||||
void checkAuthentication();
|
void checkAuthentication();
|
||||||
@@ -93,6 +96,8 @@ signals:
|
|||||||
void connectionResult( ConnectionValidator::Status status, QStringList errors );
|
void connectionResult( ConnectionValidator::Status status, QStringList errors );
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
void slotCheckServerAndAuth();
|
||||||
|
|
||||||
void slotStatusFound(const QUrl&url, const QVariantMap &info);
|
void slotStatusFound(const QUrl&url, const QVariantMap &info);
|
||||||
void slotNoStatusFound(QNetworkReply *reply);
|
void slotNoStatusFound(QNetworkReply *reply);
|
||||||
void slotJobTimeout(const QUrl& url);
|
void slotJobTimeout(const QUrl& url);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QNetworkCookie>
|
#include <QNetworkCookie>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
@@ -71,7 +72,6 @@ CookieJar::CookieJar(QObject *parent) :
|
|||||||
|
|
||||||
CookieJar::~CookieJar()
|
CookieJar::~CookieJar()
|
||||||
{
|
{
|
||||||
save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
||||||
@@ -103,7 +103,7 @@ void CookieJar::save()
|
|||||||
qDebug() << storagePath();
|
qDebug() << storagePath();
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
QDataStream stream(&file);
|
QDataStream stream(&file);
|
||||||
stream << allCookies();
|
stream << removeExpired(allCookies());
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ public:
|
|||||||
using QNetworkCookieJar::setAllCookies;
|
using QNetworkCookieJar::setAllCookies;
|
||||||
using QNetworkCookieJar::allCookies;
|
using QNetworkCookieJar::allCookies;
|
||||||
|
|
||||||
|
void save();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
private:
|
private:
|
||||||
void save();
|
|
||||||
void restore();
|
void restore();
|
||||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||||
QString storagePath() const;
|
QString storagePath() const;
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; version 2 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "creds/http/httpconfigfile.h"
|
|
||||||
|
|
||||||
namespace OCC
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
const char userC[] = "user";
|
|
||||||
const char passwdC[] = "passwd";
|
|
||||||
const char oldPasswdC[] = "password";
|
|
||||||
|
|
||||||
} // ns
|
|
||||||
|
|
||||||
QString HttpConfigFile::user() const
|
|
||||||
{
|
|
||||||
return retrieveData(QString(), QLatin1String(userC)).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpConfigFile::setUser(const QString& user)
|
|
||||||
{
|
|
||||||
storeData(QString(), QLatin1String(userC), QVariant(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString HttpConfigFile::password() const
|
|
||||||
{
|
|
||||||
const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC)));
|
|
||||||
|
|
||||||
if (passwd.isValid()) {
|
|
||||||
return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpConfigFile::setPassword(const QString& password)
|
|
||||||
{
|
|
||||||
QByteArray pwdba = password.toUtf8();
|
|
||||||
storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) );
|
|
||||||
removeOldPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HttpConfigFile::passwordExists() const
|
|
||||||
{
|
|
||||||
return dataExists(QString(), QLatin1String(passwdC));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpConfigFile::removePassword()
|
|
||||||
{
|
|
||||||
removeOldPassword();
|
|
||||||
removeData(QString(), QLatin1String(passwdC));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpConfigFile::fixupOldPassword()
|
|
||||||
{
|
|
||||||
const QString old(QString::fromLatin1(oldPasswdC));
|
|
||||||
|
|
||||||
if (dataExists(QString(), old)) {
|
|
||||||
setPassword(retrieveData(QString(), old).toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpConfigFile::removeOldPassword()
|
|
||||||
{
|
|
||||||
removeData(QString(), QLatin1String(oldPasswdC));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; version 2 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
|
||||||
#define MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
|
||||||
|
|
||||||
#include "configfile.h"
|
|
||||||
|
|
||||||
namespace OCC
|
|
||||||
{
|
|
||||||
|
|
||||||
class HttpConfigFile : public ConfigFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString user() const;
|
|
||||||
void setUser(const QString& user);
|
|
||||||
|
|
||||||
QString password() const;
|
|
||||||
void setPassword(const QString& password);
|
|
||||||
bool passwordExists() const;
|
|
||||||
void removePassword();
|
|
||||||
void fixupOldPassword();
|
|
||||||
QString certificatePath() const;
|
|
||||||
void setCertificatePath(const QString& cPath);
|
|
||||||
QString certificatePasswd() const;
|
|
||||||
void setCertificatePasswd(const QString& cPasswd);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void removeOldPassword();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -313,6 +313,9 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
|
|||||||
|
|
||||||
void HttpCredentials::invalidateToken()
|
void HttpCredentials::invalidateToken()
|
||||||
{
|
{
|
||||||
|
if (! _password.isEmpty()) {
|
||||||
|
_previousPassword = _password;
|
||||||
|
}
|
||||||
_password = QString();
|
_password = QString();
|
||||||
_ready = false;
|
_ready = false;
|
||||||
|
|
||||||
@@ -333,6 +336,14 @@ void HttpCredentials::invalidateToken()
|
|||||||
job->setKey(kck);
|
job->setKey(kck);
|
||||||
job->start();
|
job->start();
|
||||||
|
|
||||||
|
// Also ensure the password is deleted from the deprecated place
|
||||||
|
// otherwise we'd possibly read and use it again and again.
|
||||||
|
DeletePasswordJob *job2 = new DeletePasswordJob(Theme::instance()->appName());
|
||||||
|
// no job2->setSettings() call here, to make it use the deprecated location.
|
||||||
|
job2->setInsecureFallback(true);
|
||||||
|
job2->setKey(kck);
|
||||||
|
job2->start();
|
||||||
|
|
||||||
_account->clearCookieJar();
|
_account->clearCookieJar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +398,7 @@ QString HttpCredentialsGui::queryPassword(bool *ok)
|
|||||||
QString str = QInputDialog::getText(0, tr("Enter Password"),
|
QString str = QInputDialog::getText(0, tr("Enter Password"),
|
||||||
tr("Please enter %1 password for user '%2':")
|
tr("Please enter %1 password for user '%2':")
|
||||||
.arg(Theme::instance()->appNameGUI(), _user),
|
.arg(Theme::instance()->appNameGUI(), _user),
|
||||||
QLineEdit::Password, QString(), ok);
|
QLineEdit::Password, _previousPassword, ok);
|
||||||
return str;
|
return str;
|
||||||
} else {
|
} else {
|
||||||
return QString();
|
return QString();
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ private Q_SLOTS:
|
|||||||
protected:
|
protected:
|
||||||
QString _user;
|
QString _user;
|
||||||
QString _password;
|
QString _password;
|
||||||
|
QString _previousPassword;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _certificatePath;
|
QString _certificatePath;
|
||||||
@@ -74,6 +75,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class OWNCLOUDSYNC_EXPORT HttpCredentialsGui : public HttpCredentials {
|
class OWNCLOUDSYNC_EXPORT HttpCredentialsGui : public HttpCredentials {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit HttpCredentialsGui() : HttpCredentials() {}
|
explicit HttpCredentialsGui() : HttpCredentials() {}
|
||||||
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
||||||
|
|||||||
@@ -83,21 +83,11 @@ void DiscoveryJob::update_job_update_callback (bool local,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only use for error cases! It will always set an error errno
|
||||||
int get_errno_from_http_errcode( int err, const QString & reason ) {
|
int get_errno_from_http_errcode( int err, const QString & reason ) {
|
||||||
int new_errno = 0;
|
int new_errno = EIO;
|
||||||
|
|
||||||
switch(err) {
|
switch(err) {
|
||||||
case 200: /* OK */
|
|
||||||
case 201: /* Created */
|
|
||||||
case 202: /* Accepted */
|
|
||||||
case 203: /* Non-Authoritative Information */
|
|
||||||
case 204: /* No Content */
|
|
||||||
case 205: /* Reset Content */
|
|
||||||
case 207: /* Multi-Status */
|
|
||||||
case 304: /* Not Modified */
|
|
||||||
new_errno = 0;
|
|
||||||
break;
|
|
||||||
case 401: /* Unauthorized */
|
case 401: /* Unauthorized */
|
||||||
case 402: /* Payment Required */
|
case 402: /* Payment Required */
|
||||||
case 407: /* Proxy Authentication Required */
|
case 407: /* Proxy Authentication Required */
|
||||||
@@ -268,8 +258,11 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
csync_vio_file_stat_t *file_stat = propertyMapToFileStat(map);
|
FileStatPointer file_stat(propertyMapToFileStat(map));
|
||||||
file_stat->name = strdup(file.toUtf8());
|
file_stat->name = strdup(file.toUtf8());
|
||||||
|
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
|
||||||
|
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
|
||||||
|
}
|
||||||
//qDebug() << "!!!!" << file_stat << file_stat->name << file_stat->file_id << map.count();
|
//qDebug() << "!!!!" << file_stat << file_stat->name << file_stat->file_id << map.count();
|
||||||
_results.append(file_stat);
|
_results.append(file_stat);
|
||||||
}
|
}
|
||||||
@@ -282,6 +275,13 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap
|
|||||||
|
|
||||||
void DiscoverySingleDirectoryJob::lsJobFinishedWithoutErrorSlot()
|
void DiscoverySingleDirectoryJob::lsJobFinishedWithoutErrorSlot()
|
||||||
{
|
{
|
||||||
|
if (!_ignoredFirst) {
|
||||||
|
// This is a sanity check, if we haven't _ignoredFirst then it means we never received any directoryListingIteratedSlot
|
||||||
|
// which means somehow the server XML was bogus
|
||||||
|
emit finishedWithError(ERRNO_WRONG_CONTENT, QLatin1String("Server error: PROPFIND reply is not XML formatted!"));
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
emit etagConcatenation(_etagConcatenation);
|
emit etagConcatenation(_etagConcatenation);
|
||||||
emit finishedWithResult(_results);
|
emit finishedWithResult(_results);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
@@ -293,7 +293,7 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r)
|
|||||||
int httpCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int httpCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
QString httpReason = r->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
QString httpReason = r->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||||
QString msg = r->errorString();
|
QString msg = r->errorString();
|
||||||
int errnoCode = 0;
|
int errnoCode = EIO; // Something went wrong
|
||||||
qDebug() << Q_FUNC_INFO << r->errorString() << httpCode << r->error();
|
qDebug() << Q_FUNC_INFO << r->errorString() << httpCode << r->error();
|
||||||
if (httpCode != 0 && httpCode != 207) {
|
if (httpCode != 0 && httpCode != 207) {
|
||||||
errnoCode = get_errno_from_http_errcode(httpCode, httpReason);
|
errnoCode = get_errno_from_http_errcode(httpCode, httpReason);
|
||||||
@@ -302,9 +302,11 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r)
|
|||||||
} else if (!contentType.contains("application/xml; charset=utf-8")) {
|
} else if (!contentType.contains("application/xml; charset=utf-8")) {
|
||||||
msg = QLatin1String("Server error: PROPFIND reply is not XML formatted!");
|
msg = QLatin1String("Server error: PROPFIND reply is not XML formatted!");
|
||||||
errnoCode = ERRNO_WRONG_CONTENT;
|
errnoCode = ERRNO_WRONG_CONTENT;
|
||||||
|
} else {
|
||||||
|
// Default keep at EIO, see above
|
||||||
}
|
}
|
||||||
|
|
||||||
emit finishedWithError(errnoCode, msg);
|
emit finishedWithError(errnoCode == 0 ? EIO : errnoCode, msg);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,15 +318,6 @@ void DiscoveryMainThread::setupHooks(DiscoveryJob *discoveryJob, const QString &
|
|||||||
connect(discoveryJob, SIGNAL(doOpendirSignal(QString,DiscoveryDirectoryResult*)),
|
connect(discoveryJob, SIGNAL(doOpendirSignal(QString,DiscoveryDirectoryResult*)),
|
||||||
this, SLOT(doOpendirSlot(QString,DiscoveryDirectoryResult*)),
|
this, SLOT(doOpendirSlot(QString,DiscoveryDirectoryResult*)),
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(discoveryJob, SIGNAL(doClosedirSignal(QString)),
|
|
||||||
this, SLOT(doClosedirSlot(QString)),
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DiscoveryMainThread::doClosedirSlot(QString path)
|
|
||||||
{
|
|
||||||
//qDebug() << Q_FUNC_INFO << "Invalidating" << path;
|
|
||||||
deleteCacheEntry(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coming from owncloud_opendir -> DiscoveryJob::vio_opendir_hook -> doOpendirSignal
|
// Coming from owncloud_opendir -> DiscoveryJob::vio_opendir_hook -> doOpendirSignal
|
||||||
@@ -349,8 +342,8 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul
|
|||||||
|
|
||||||
// Schedule the DiscoverySingleDirectoryJob
|
// Schedule the DiscoverySingleDirectoryJob
|
||||||
_singleDirJob = new DiscoverySingleDirectoryJob(_account, fullPath, this);
|
_singleDirJob = new DiscoverySingleDirectoryJob(_account, fullPath, this);
|
||||||
QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t *>)),
|
QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(const QList<FileStatPointer> &)),
|
||||||
this, SLOT(singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>)));
|
this, SLOT(singleDirectoryJobResultSlot(const QList<FileStatPointer> &)));
|
||||||
QObject::connect(_singleDirJob, SIGNAL(finishedWithError(int,QString)),
|
QObject::connect(_singleDirJob, SIGNAL(finishedWithError(int,QString)),
|
||||||
this, SLOT(singleDirectoryJobFinishedWithErrorSlot(int,QString)));
|
this, SLOT(singleDirectoryJobFinishedWithErrorSlot(int,QString)));
|
||||||
QObject::connect(_singleDirJob, SIGNAL(firstDirectoryPermissions(QString)),
|
QObject::connect(_singleDirJob, SIGNAL(firstDirectoryPermissions(QString)),
|
||||||
@@ -361,7 +354,7 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t *> result)
|
void DiscoveryMainThread::singleDirectoryJobResultSlot(const QList<FileStatPointer> & result)
|
||||||
{
|
{
|
||||||
if (!_currentDiscoveryDirectoryResult) {
|
if (!_currentDiscoveryDirectoryResult) {
|
||||||
return; // possibly aborted
|
return; // possibly aborted
|
||||||
@@ -369,11 +362,9 @@ void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_fil
|
|||||||
qDebug() << Q_FUNC_INFO << "Have" << result.count() << "results for " << _currentDiscoveryDirectoryResult->path;
|
qDebug() << Q_FUNC_INFO << "Have" << result.count() << "results for " << _currentDiscoveryDirectoryResult->path;
|
||||||
|
|
||||||
|
|
||||||
_directoryContents.insert(_currentDiscoveryDirectoryResult->path, result);
|
|
||||||
|
|
||||||
_currentDiscoveryDirectoryResult->list = result;
|
_currentDiscoveryDirectoryResult->list = result;
|
||||||
_currentDiscoveryDirectoryResult->code = 0;
|
_currentDiscoveryDirectoryResult->code = 0;
|
||||||
_currentDiscoveryDirectoryResult->iterator = _currentDiscoveryDirectoryResult->list.begin();
|
_currentDiscoveryDirectoryResult->listIndex = 0;
|
||||||
_currentDiscoveryDirectoryResult = 0; // the sync thread owns it now
|
_currentDiscoveryDirectoryResult = 0; // the sync thread owns it now
|
||||||
|
|
||||||
_discoveryJob->_vioMutex.lock();
|
_discoveryJob->_vioMutex.lock();
|
||||||
@@ -411,7 +402,7 @@ void DiscoveryMainThread::abort() {
|
|||||||
if (_singleDirJob) {
|
if (_singleDirJob) {
|
||||||
_singleDirJob->disconnect(SIGNAL(finishedWithError(int,QString)), this);
|
_singleDirJob->disconnect(SIGNAL(finishedWithError(int,QString)), this);
|
||||||
_singleDirJob->disconnect(SIGNAL(firstDirectoryPermissions(QString)), this);
|
_singleDirJob->disconnect(SIGNAL(firstDirectoryPermissions(QString)), this);
|
||||||
_singleDirJob->disconnect(SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t*>)), this);
|
_singleDirJob->disconnect(SIGNAL(finishedWithResult(const QList<FileStatPointer> &)), this);
|
||||||
_singleDirJob->abort();
|
_singleDirJob->abort();
|
||||||
}
|
}
|
||||||
if (_currentDiscoveryDirectoryResult) {
|
if (_currentDiscoveryDirectoryResult) {
|
||||||
@@ -466,9 +457,8 @@ csync_vio_file_stat_t* DiscoveryJob::remote_vio_readdir_hook (csync_vio_handle_t
|
|||||||
DiscoveryJob *discoveryJob = static_cast<DiscoveryJob*>(userdata);
|
DiscoveryJob *discoveryJob = static_cast<DiscoveryJob*>(userdata);
|
||||||
if (discoveryJob) {
|
if (discoveryJob) {
|
||||||
DiscoveryDirectoryResult *directoryResult = static_cast<DiscoveryDirectoryResult*>(dhandle);
|
DiscoveryDirectoryResult *directoryResult = static_cast<DiscoveryDirectoryResult*>(dhandle);
|
||||||
if (directoryResult->iterator != directoryResult->list.end()) {
|
if (directoryResult->listIndex < directoryResult->list.size()) {
|
||||||
csync_vio_file_stat_t *file_stat = *(directoryResult->iterator);
|
csync_vio_file_stat_t *file_stat = directoryResult->list.at(directoryResult->listIndex++).data();
|
||||||
directoryResult->iterator++;
|
|
||||||
// Make a copy, csync_update will delete the copy
|
// Make a copy, csync_update will delete the copy
|
||||||
return csync_vio_file_stat_copy(file_stat);
|
return csync_vio_file_stat_copy(file_stat);
|
||||||
}
|
}
|
||||||
@@ -484,7 +474,6 @@ void DiscoveryJob::remote_vio_closedir_hook (csync_vio_handle_t *dhandle, void
|
|||||||
QString path = directoryResult->path;
|
QString path = directoryResult->path;
|
||||||
qDebug() << Q_FUNC_INFO << discoveryJob << path;
|
qDebug() << Q_FUNC_INFO << discoveryJob << path;
|
||||||
delete directoryResult; // just deletes the struct and the iterator, the data itself is owned by the SyncEngine/DiscoveryMainThread
|
delete directoryResult; // just deletes the struct and the iterator, the data itself is owned by the SyncEngine/DiscoveryMainThread
|
||||||
emit discoveryJob->doClosedirSignal(path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,36 @@ class Account;
|
|||||||
* if the files are new, or changed.
|
* if the files are new, or changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class FileStatPointer {
|
||||||
|
public:
|
||||||
|
FileStatPointer(csync_vio_file_stat_t *stat)
|
||||||
|
: _stat(stat)
|
||||||
|
{ }
|
||||||
|
FileStatPointer(const FileStatPointer &other)
|
||||||
|
: _stat(csync_vio_file_stat_copy(other._stat))
|
||||||
|
{ }
|
||||||
|
~FileStatPointer() {
|
||||||
|
csync_vio_file_stat_destroy(_stat);
|
||||||
|
}
|
||||||
|
FileStatPointer &operator=(const FileStatPointer &other) {
|
||||||
|
csync_vio_file_stat_destroy(_stat);
|
||||||
|
_stat = csync_vio_file_stat_copy(other._stat);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline csync_vio_file_stat_t *data() const { return _stat; }
|
||||||
|
inline csync_vio_file_stat_t *operator->() const { return _stat; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
csync_vio_file_stat_t *_stat;
|
||||||
|
};
|
||||||
|
|
||||||
struct DiscoveryDirectoryResult {
|
struct DiscoveryDirectoryResult {
|
||||||
QString path;
|
QString path;
|
||||||
QString msg;
|
QString msg;
|
||||||
int code;
|
int code;
|
||||||
QLinkedList<csync_vio_file_stat_t*>::iterator iterator;
|
QList<FileStatPointer> list;
|
||||||
QLinkedList<csync_vio_file_stat_t *> list;
|
int listIndex;
|
||||||
|
DiscoveryDirectoryResult() : code(EIO), listIndex(0) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run in the main thread, reporting to the DiscoveryJobMainThread object
|
// Run in the main thread, reporting to the DiscoveryJobMainThread object
|
||||||
@@ -53,14 +77,14 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void firstDirectoryPermissions(const QString &);
|
void firstDirectoryPermissions(const QString &);
|
||||||
void etagConcatenation(const QString &);
|
void etagConcatenation(const QString &);
|
||||||
void finishedWithResult(QLinkedList<csync_vio_file_stat_t*>);
|
void finishedWithResult(const QList<FileStatPointer> &);
|
||||||
void finishedWithError(int csyncErrnoCode, QString msg);
|
void finishedWithError(int csyncErrnoCode, QString msg);
|
||||||
private slots:
|
private slots:
|
||||||
void directoryListingIteratedSlot(QString,QMap<QString,QString>);
|
void directoryListingIteratedSlot(QString,QMap<QString,QString>);
|
||||||
void lsJobFinishedWithoutErrorSlot();
|
void lsJobFinishedWithoutErrorSlot();
|
||||||
void lsJobFinishedWithErrorSlot(QNetworkReply*);
|
void lsJobFinishedWithErrorSlot(QNetworkReply*);
|
||||||
private:
|
private:
|
||||||
QLinkedList<csync_vio_file_stat_t*> _results;
|
QList<FileStatPointer> _results;
|
||||||
QString _subPath;
|
QString _subPath;
|
||||||
QString _etagConcatenation;
|
QString _etagConcatenation;
|
||||||
AccountPtr _account;
|
AccountPtr _account;
|
||||||
@@ -73,11 +97,6 @@ class DiscoveryJob;
|
|||||||
class DiscoveryMainThread : public QObject {
|
class DiscoveryMainThread : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
// For non-recursive and recursive
|
|
||||||
// If it is not in this map it needs to be requested
|
|
||||||
QMap<QString, QLinkedList<csync_vio_file_stat_t*> > _directoryContents;
|
|
||||||
|
|
||||||
|
|
||||||
QPointer<DiscoveryJob> _discoveryJob;
|
QPointer<DiscoveryJob> _discoveryJob;
|
||||||
QPointer<DiscoverySingleDirectoryJob> _singleDirJob;
|
QPointer<DiscoverySingleDirectoryJob> _singleDirJob;
|
||||||
QString _pathPrefix;
|
QString _pathPrefix;
|
||||||
@@ -87,22 +106,6 @@ class DiscoveryMainThread : public QObject {
|
|||||||
public:
|
public:
|
||||||
DiscoveryMainThread(AccountPtr account) : QObject(), _account(account), _currentDiscoveryDirectoryResult(0) {
|
DiscoveryMainThread(AccountPtr account) : QObject(), _account(account), _currentDiscoveryDirectoryResult(0) {
|
||||||
|
|
||||||
}
|
|
||||||
void deleteCacheEntry(QString path) {
|
|
||||||
//qDebug() << path << _directoryContents.value(path).count();
|
|
||||||
foreach (csync_vio_file_stat_t* stat, _directoryContents.value(path)) {
|
|
||||||
csync_vio_file_stat_destroy(stat);
|
|
||||||
}
|
|
||||||
_directoryContents.remove(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DiscoveryMainThread() {
|
|
||||||
// Delete the _contents_ of the list-map explicitly:
|
|
||||||
foreach (const QLinkedList<csync_vio_file_stat_t*> & list, _directoryContents) {
|
|
||||||
foreach (csync_vio_file_stat_t* stat, list) {
|
|
||||||
csync_vio_file_stat_destroy(stat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
@@ -110,10 +113,9 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
// From DiscoveryJob:
|
// From DiscoveryJob:
|
||||||
void doOpendirSlot(QString url, DiscoveryDirectoryResult* );
|
void doOpendirSlot(QString url, DiscoveryDirectoryResult* );
|
||||||
void doClosedirSlot(QString path);
|
|
||||||
|
|
||||||
// From Job:
|
// From Job:
|
||||||
void singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>);
|
void singleDirectoryJobResultSlot(const QList<FileStatPointer> &);
|
||||||
void singleDirectoryJobFinishedWithErrorSlot(int csyncErrnoCode, QString msg);
|
void singleDirectoryJobFinishedWithErrorSlot(int csyncErrnoCode, QString msg);
|
||||||
void singleDirectoryJobFirstDirectoryPermissionsSlot(QString);
|
void singleDirectoryJobFirstDirectoryPermissionsSlot(QString);
|
||||||
signals:
|
signals:
|
||||||
@@ -175,8 +177,6 @@ signals:
|
|||||||
|
|
||||||
// After the discovery job has been woken up again (_vioWaitCondition)
|
// After the discovery job has been woken up again (_vioWaitCondition)
|
||||||
void doOpendirSignal(QString url, DiscoveryDirectoryResult*);
|
void doOpendirSignal(QString url, DiscoveryDirectoryResult*);
|
||||||
// to tell the main thread to invalidate its directory data
|
|
||||||
void doClosedirSignal(QString path);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,12 @@ AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path,
|
|||||||
|
|
||||||
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
if (_reply) {
|
if (reply)
|
||||||
_reply->deleteLater();
|
reply->setProperty("doNotHandleAuth", true);
|
||||||
}
|
|
||||||
reply->setProperty("doNotHandleAuth", true);
|
QNetworkReply *old = _reply;
|
||||||
_reply = reply;
|
_reply = reply;
|
||||||
|
delete old;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractNetworkJob::setTimeout(qint64 msec)
|
void AbstractNetworkJob::setTimeout(qint64 msec)
|
||||||
@@ -213,9 +214,7 @@ QByteArray AbstractNetworkJob::responseTimestamp()
|
|||||||
|
|
||||||
AbstractNetworkJob::~AbstractNetworkJob()
|
AbstractNetworkJob::~AbstractNetworkJob()
|
||||||
{
|
{
|
||||||
if (_reply) {
|
setReply(0);
|
||||||
_reply->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractNetworkJob::start()
|
void AbstractNetworkJob::start()
|
||||||
@@ -224,7 +223,10 @@ void AbstractNetworkJob::start()
|
|||||||
_durationTimer.start();
|
_durationTimer.start();
|
||||||
_duration = 0;
|
_duration = 0;
|
||||||
|
|
||||||
qDebug() << "!!!" << metaObject()->className() << "created for" << account()->url() << "querying" << path();
|
const QUrl url = account()->url();
|
||||||
|
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||||
|
|
||||||
|
qDebug() << "!!!" << metaObject()->className() << "created for" << displayUrl << "+" << path();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractNetworkJob::slotTimeout()
|
void AbstractNetworkJob::slotTimeout()
|
||||||
@@ -318,6 +320,131 @@ bool MkColJob::finished()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************/
|
||||||
|
// supposed to read <D:collection> when pointing to <D:resourcetype><D:collection></D:resourcetype>..
|
||||||
|
static QString readContentsAsString(QXmlStreamReader &reader) {
|
||||||
|
QString result;
|
||||||
|
int level = 0;
|
||||||
|
do {
|
||||||
|
QXmlStreamReader::TokenType type = reader.readNext();
|
||||||
|
if (type == QXmlStreamReader::StartElement) {
|
||||||
|
level++;
|
||||||
|
result += "<" + reader.name().toString() + ">";
|
||||||
|
} else if (type == QXmlStreamReader::Characters) {
|
||||||
|
result += reader.text();
|
||||||
|
} else if (type == QXmlStreamReader::EndElement) {
|
||||||
|
level--;
|
||||||
|
if (level < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result += "</" + reader.name().toString() + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!reader.atEnd());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LsColXMLParser::LsColXMLParser()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes)
|
||||||
|
{
|
||||||
|
// Parse DAV response
|
||||||
|
QXmlStreamReader reader(xml);
|
||||||
|
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||||
|
|
||||||
|
QStringList folders;
|
||||||
|
QString currentHref;
|
||||||
|
QMap<QString, QString> currentTmpProperties;
|
||||||
|
QMap<QString, QString> currentHttp200Properties;
|
||||||
|
bool currentPropsHaveHttp200 = false;
|
||||||
|
bool insidePropstat = false;
|
||||||
|
bool insideProp = false;
|
||||||
|
bool insideMultiStatus = false;
|
||||||
|
|
||||||
|
while (!reader.atEnd()) {
|
||||||
|
QXmlStreamReader::TokenType type = reader.readNext();
|
||||||
|
QString name = reader.name().toString();
|
||||||
|
// Start elements with DAV:
|
||||||
|
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
|
if (name == QLatin1String("href")) {
|
||||||
|
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
|
||||||
|
} else if (name == QLatin1String("response")) {
|
||||||
|
} else if (name == QLatin1String("propstat")) {
|
||||||
|
insidePropstat = true;
|
||||||
|
} else if (name == QLatin1String("status") && insidePropstat) {
|
||||||
|
QString httpStatus = reader.readElementText();
|
||||||
|
if (httpStatus.startsWith("HTTP/1.1 200")) {
|
||||||
|
currentPropsHaveHttp200 = true;
|
||||||
|
} else {
|
||||||
|
currentPropsHaveHttp200 = false;
|
||||||
|
}
|
||||||
|
} else if (name == QLatin1String("prop")) {
|
||||||
|
insideProp = true;
|
||||||
|
continue;
|
||||||
|
} else if (name == QLatin1String("multistatus")) {
|
||||||
|
insideMultiStatus = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) {
|
||||||
|
// All those elements are properties
|
||||||
|
QString propertyContent = readContentsAsString(reader);
|
||||||
|
if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) {
|
||||||
|
folders.append(currentHref);
|
||||||
|
} else if (name == QLatin1String("quota-used-bytes")) {
|
||||||
|
bool ok = false;
|
||||||
|
auto s = propertyContent.toLongLong(&ok);
|
||||||
|
if (ok && sizes) {
|
||||||
|
sizes->insert(currentHref, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentTmpProperties.insert(reader.name().toString(), propertyContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// End elements with DAV:
|
||||||
|
if (type == QXmlStreamReader::EndElement) {
|
||||||
|
if (reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
|
if (reader.name() == "response") {
|
||||||
|
if (currentHref.endsWith('/')) {
|
||||||
|
currentHref.chop(1);
|
||||||
|
}
|
||||||
|
emit directoryListingIterated(currentHref, currentHttp200Properties);
|
||||||
|
currentHref.clear();
|
||||||
|
currentHttp200Properties.clear();
|
||||||
|
} else if (reader.name() == "propstat") {
|
||||||
|
insidePropstat = false;
|
||||||
|
if (currentPropsHaveHttp200) {
|
||||||
|
currentHttp200Properties = QMap<QString,QString>(currentTmpProperties);
|
||||||
|
}
|
||||||
|
currentTmpProperties.clear();
|
||||||
|
currentPropsHaveHttp200 = false;
|
||||||
|
} else if (reader.name() == "prop") {
|
||||||
|
insideProp = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.hasError()) {
|
||||||
|
// XML Parser error? Whatever had been emitted before will come as directoryListingIterated
|
||||||
|
qDebug() << "ERROR" << reader.errorString() << xml;
|
||||||
|
return false;
|
||||||
|
} else if (!insideMultiStatus) {
|
||||||
|
qDebug() << "ERROR no WebDAV response?" << xml;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
emit directoryListingSubfolders(folders);
|
||||||
|
emit finishedWithoutError();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
LsColJob::LsColJob(AccountPtr account, const QString &path, QObject *parent)
|
LsColJob::LsColJob(AccountPtr account, const QString &path, QObject *parent)
|
||||||
@@ -375,117 +502,36 @@ void LsColJob::start()
|
|||||||
AbstractNetworkJob::start();
|
AbstractNetworkJob::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// supposed to read <D:collection> when pointing to <D:resourcetype><D:collection></D:resourcetype>..
|
// TODO: Instead of doing all in this slot, we should iteratively parse in readyRead(). This
|
||||||
static QString readContentsAsString(QXmlStreamReader &reader) {
|
// would allow us to be more asynchronous in processing while data is coming from the network,
|
||||||
QString result;
|
// not in all in one big blobb at the end.
|
||||||
int level = 0;
|
|
||||||
do {
|
|
||||||
QXmlStreamReader::TokenType type = reader.readNext();
|
|
||||||
if (type == QXmlStreamReader::StartElement) {
|
|
||||||
level++;
|
|
||||||
result += "<" + reader.name().toString() + ">";
|
|
||||||
} else if (type == QXmlStreamReader::Characters) {
|
|
||||||
result += reader.text();
|
|
||||||
} else if (type == QXmlStreamReader::EndElement) {
|
|
||||||
level--;
|
|
||||||
if (level < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result += "</" + reader.name().toString() + ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (!reader.atEnd());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LsColJob::finished()
|
bool LsColJob::finished()
|
||||||
{
|
{
|
||||||
QString contentType = reply()->header(QNetworkRequest::ContentTypeHeader).toString();
|
QString contentType = reply()->header(QNetworkRequest::ContentTypeHeader).toString();
|
||||||
int httpCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int httpCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if (httpCode == 207 && contentType.contains("application/xml; charset=utf-8")) {
|
if (httpCode == 207 && contentType.contains("application/xml; charset=utf-8")) {
|
||||||
// Parse DAV response
|
LsColXMLParser parser;
|
||||||
QByteArray xml = reply()->readAll();
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
QXmlStreamReader reader(xml);
|
this, SIGNAL(directoryListingSubfolders(const QStringList&)) );
|
||||||
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithError(QNetworkReply *)),
|
||||||
|
this, SIGNAL(finishedWithError(QNetworkReply *)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SIGNAL(finishedWithoutError()) );
|
||||||
|
|
||||||
QStringList folders;
|
if( !parser.parse( reply()->readAll(), &_sizes ) ) {
|
||||||
QString currentHref;
|
// XML parse error
|
||||||
QMap<QString, QString> currentTmpProperties;
|
emit finishedWithError(reply());
|
||||||
QMap<QString, QString> currentHttp200Properties;
|
|
||||||
bool currentPropsHaveHttp200 = false;
|
|
||||||
bool insidePropstat = false;
|
|
||||||
bool insideProp = false;
|
|
||||||
|
|
||||||
while (!reader.atEnd()) {
|
|
||||||
QXmlStreamReader::TokenType type = reader.readNext();
|
|
||||||
QString name = reader.name().toString();
|
|
||||||
// Start elements with DAV:
|
|
||||||
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
|
||||||
if (name == QLatin1String("href")) {
|
|
||||||
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
|
|
||||||
} else if (name == QLatin1String("response")) {
|
|
||||||
} else if (name == QLatin1String("propstat")) {
|
|
||||||
insidePropstat = true;
|
|
||||||
} else if (name == QLatin1String("status") && insidePropstat) {
|
|
||||||
QString httpStatus = reader.readElementText();
|
|
||||||
if (httpStatus.startsWith("HTTP/1.1 200")) {
|
|
||||||
currentPropsHaveHttp200 = true;
|
|
||||||
} else {
|
|
||||||
currentPropsHaveHttp200 = false;
|
|
||||||
}
|
|
||||||
} else if (name == QLatin1String("prop")) {
|
|
||||||
insideProp = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) {
|
|
||||||
// All those elements are properties
|
|
||||||
QString propertyContent = readContentsAsString(reader);
|
|
||||||
if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) {
|
|
||||||
folders.append(currentHref);
|
|
||||||
} else if (name == QLatin1String("quota-used-bytes")) {
|
|
||||||
bool ok = false;
|
|
||||||
auto s = propertyContent.toLongLong(&ok);
|
|
||||||
if (ok) {
|
|
||||||
_sizes[currentHref] = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentTmpProperties.insert(reader.name().toString(), propertyContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// End elements with DAV:
|
|
||||||
if (type == QXmlStreamReader::EndElement) {
|
|
||||||
if (reader.namespaceUri() == QLatin1String("DAV:")) {
|
|
||||||
if (reader.name() == "response") {
|
|
||||||
if (currentHref.endsWith('/')) {
|
|
||||||
currentHref.chop(1);
|
|
||||||
}
|
|
||||||
emit directoryListingIterated(currentHref, currentHttp200Properties);
|
|
||||||
currentHref.clear();
|
|
||||||
currentHttp200Properties.clear();
|
|
||||||
} else if (reader.name() == "propstat") {
|
|
||||||
insidePropstat = false;
|
|
||||||
if (currentPropsHaveHttp200) {
|
|
||||||
currentHttp200Properties = QMap<QString,QString>(currentTmpProperties);
|
|
||||||
}
|
|
||||||
currentTmpProperties.clear();
|
|
||||||
currentPropsHaveHttp200 = false;
|
|
||||||
} else if (reader.name() == "prop") {
|
|
||||||
insideProp = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
emit directoryListingSubfolders(folders);
|
|
||||||
emit finishedWithoutError();
|
|
||||||
} else if (httpCode == 207) {
|
} else if (httpCode == 207) {
|
||||||
// wrong content type
|
// wrong content type
|
||||||
emit finishedWithError(reply());
|
emit finishedWithError(reply());
|
||||||
} else {
|
} else {
|
||||||
// wrong HTTP code
|
// wrong HTTP code or any other network error
|
||||||
emit finishedWithError(reply());
|
emit finishedWithError(reply());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,8 +694,9 @@ bool PropfindJob::finished()
|
|||||||
if (type == QXmlStreamReader::StartElement) {
|
if (type == QXmlStreamReader::StartElement) {
|
||||||
if (!curElement.isEmpty() && curElement.top() == QLatin1String("prop")) {
|
if (!curElement.isEmpty() && curElement.top() == QLatin1String("prop")) {
|
||||||
items.insert(reader.name().toString(), reader.readElementText());
|
items.insert(reader.name().toString(), reader.readElementText());
|
||||||
|
} else {
|
||||||
|
curElement.push(reader.name().toString());
|
||||||
}
|
}
|
||||||
curElement.push(reader.name().toString());
|
|
||||||
}
|
}
|
||||||
if (type == QXmlStreamReader::EndElement) {
|
if (type == QXmlStreamReader::EndElement) {
|
||||||
if(curElement.top() == reader.name()) {
|
if(curElement.top() == reader.name()) {
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ protected:
|
|||||||
QElapsedTimer _durationTimer;
|
QElapsedTimer _durationTimer;
|
||||||
quint64 _duration;
|
quint64 _duration;
|
||||||
bool _timedout; // set to true when the timeout slot is recieved
|
bool _timedout; // set to true when the timeout slot is recieved
|
||||||
|
|
||||||
|
// Automatically follows redirects. Note that this only works for
|
||||||
|
// GET requests that don't set up any HTTP body or other flags.
|
||||||
bool _followRedirects;
|
bool _followRedirects;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -129,6 +132,21 @@ private slots:
|
|||||||
/**
|
/**
|
||||||
* @brief The LsColJob class
|
* @brief The LsColJob class
|
||||||
*/
|
*/
|
||||||
|
class OWNCLOUDSYNC_EXPORT LsColXMLParser : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit LsColXMLParser();
|
||||||
|
|
||||||
|
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void directoryListingSubfolders(const QStringList &items);
|
||||||
|
void directoryListingIterated(const QString &name, const QMap<QString,QString> &properties);
|
||||||
|
void finishedWithError(QNetworkReply *reply);
|
||||||
|
void finishedWithoutError();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class OWNCLOUDSYNC_EXPORT LsColJob : public AbstractNetworkJob {
|
class OWNCLOUDSYNC_EXPORT LsColJob : public AbstractNetworkJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "account.h"
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -40,9 +41,13 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
OwncloudPropagator::~OwncloudPropagator()
|
||||||
|
{}
|
||||||
|
|
||||||
/* The maximum number of active job in parallel */
|
/* The maximum number of active job in parallel */
|
||||||
int OwncloudPropagator::maximumActiveJob()
|
int OwncloudPropagator::maximumActiveJob()
|
||||||
{
|
{
|
||||||
@@ -631,6 +636,9 @@ void PropagateDirectory::finalize()
|
|||||||
emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
|
emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CleanupPollsJob::~CleanupPollsJob()
|
||||||
|
{}
|
||||||
|
|
||||||
void CleanupPollsJob::start()
|
void CleanupPollsJob::start()
|
||||||
{
|
{
|
||||||
if (_pollInfos.empty()) {
|
if (_pollInfos.empty()) {
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ public:
|
|||||||
, _account(account)
|
, _account(account)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
~OwncloudPropagator();
|
||||||
|
|
||||||
void start(const SyncFileItemVector &_syncedItems);
|
void start(const SyncFileItemVector &_syncedItems);
|
||||||
|
|
||||||
QAtomicInt _downloadLimit;
|
QAtomicInt _downloadLimit;
|
||||||
@@ -359,6 +361,8 @@ public:
|
|||||||
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
|
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
|
||||||
: QObject(parent), _pollInfos(pollInfos), _account(account), _journal(journal), _localPath(localPath) {}
|
: QObject(parent), _pollInfos(pollInfos), _account(account), _journal(journal), _localPath(localPath) {}
|
||||||
|
|
||||||
|
~CleanupPollsJob();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QDebug>
|
||||||
#include "syncfileitem.h"
|
#include "syncfileitem.h"
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
@@ -33,9 +34,14 @@ inline QByteArray parseEtag(const char *header) {
|
|||||||
|
|
||||||
inline QByteArray getEtagFromReply(QNetworkReply *reply)
|
inline QByteArray getEtagFromReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
QByteArray ret = parseEtag(reply->rawHeader("OC-ETag"));
|
QByteArray ocEtag = parseEtag(reply->rawHeader("OC-ETag"));
|
||||||
|
QByteArray etag = parseEtag(reply->rawHeader("ETag"));
|
||||||
|
QByteArray ret = ocEtag;
|
||||||
if (ret.isEmpty()) {
|
if (ret.isEmpty()) {
|
||||||
ret = parseEtag(reply->rawHeader("ETag"));
|
ret = etag;
|
||||||
|
}
|
||||||
|
if (ocEtag.length() > 0 && ocEtag != etag) {
|
||||||
|
qDebug() << "Quite peculiar, we have an etag != OC-Etag [no problem!]" << etag << ocEtag;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDebug>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
@@ -338,6 +339,7 @@ void PropagateDownloadFileQNAM::start()
|
|||||||
if (startSize > 0) {
|
if (startSize > 0) {
|
||||||
if (startSize == _item._size) {
|
if (startSize == _item._size) {
|
||||||
qDebug() << "File is already complete, no need to download";
|
qDebug() << "File is already complete, no need to download";
|
||||||
|
_tmpFile.close();
|
||||||
downloadFinished();
|
downloadFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -368,6 +370,7 @@ void PropagateDownloadFileQNAM::start()
|
|||||||
_job->start();
|
_job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
|
||||||
void PropagateDownloadFileQNAM::slotGetFinished()
|
void PropagateDownloadFileQNAM::slotGetFinished()
|
||||||
{
|
{
|
||||||
_propagator->_activeJobs--;
|
_propagator->_activeJobs--;
|
||||||
@@ -407,7 +410,18 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This gives a custom QNAM (by the user of libowncloudsync) to abort() a QNetworkReply in its metaDataChanged() slot and
|
||||||
|
// set a custom error string to make this a soft error. In contrast to the default hard error this won't bring down
|
||||||
|
// the whole sync and allows for a custom error message.
|
||||||
|
QNetworkReply *reply = job->reply();
|
||||||
|
if (err == QNetworkReply::OperationCanceledError && reply->property(owncloudCustomSoftErrorStringC).isValid()) {
|
||||||
|
job->setErrorString(reply->property(owncloudCustomSoftErrorStringC).toString());
|
||||||
|
job->setErrorStatus(SyncFileItem::SoftError);
|
||||||
|
}
|
||||||
|
|
||||||
SyncFileItem::Status status = job->errorStatus();
|
SyncFileItem::Status status = job->errorStatus();
|
||||||
|
|
||||||
|
|
||||||
if (status == SyncFileItem::NoStatus) {
|
if (status == SyncFileItem::NoStatus) {
|
||||||
status = classifyError(err, _item._httpErrorCode);
|
status = classifyError(err, _item._httpErrorCode);
|
||||||
}
|
}
|
||||||
@@ -476,7 +490,6 @@ QString makeConflictFileName(const QString &fn, const QDateTime &dt)
|
|||||||
|
|
||||||
void PropagateDownloadFileQNAM::downloadFinished()
|
void PropagateDownloadFileQNAM::downloadFinished()
|
||||||
{
|
{
|
||||||
|
|
||||||
QString fn = _propagator->getFilePath(_item._file);
|
QString fn = _propagator->getFilePath(_item._file);
|
||||||
|
|
||||||
// In case of file name clash, report an error
|
// In case of file name clash, report an error
|
||||||
@@ -506,10 +519,14 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
_tmpFile.setPermissions(existingFile.permissions());
|
_tmpFile.setPermissions(existingFile.permissions());
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystem::setFileHidden(_tmpFile.fileName(), false);
|
FileSystem::setModTime(_tmpFile.fileName(), _item._modtime);
|
||||||
|
// We need to fetch the time again because some file system such as FAT have a less than a second
|
||||||
|
// Accuracy, and we really need the time from the file system. (#3103)
|
||||||
|
_item._modtime = FileSystem::getModTime(_tmpFile.fileName());
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
_propagator->addTouchedFile(fn);
|
_propagator->addTouchedFile(fn);
|
||||||
|
FileSystem::setFileHidden(_tmpFile.fileName(), false);
|
||||||
if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) {
|
if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) {
|
||||||
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
||||||
// If we moved away the original file due to a conflict but can't
|
// If we moved away the original file due to a conflict but can't
|
||||||
@@ -530,7 +547,6 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
|
|
||||||
// Maybe we downloaded a newer version of the file than we thought we would...
|
// Maybe we downloaded a newer version of the file than we thought we would...
|
||||||
// Get up to date information for the journal.
|
// Get up to date information for the journal.
|
||||||
FileSystem::setModTime(fn, _item._modtime);
|
|
||||||
_item._size = FileSystem::getSize(fn);
|
_item._size = FileSystem::getSize(fn);
|
||||||
|
|
||||||
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn));
|
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn));
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ public:
|
|||||||
qint64 currentDownloadPosition();
|
qint64 currentDownloadPosition();
|
||||||
|
|
||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
void setErrorString(const QString& s) { _errorString = s; }
|
||||||
|
|
||||||
SyncFileItem::Status errorStatus() { return _errorStatus; }
|
SyncFileItem::Status errorStatus() { return _errorStatus; }
|
||||||
|
void setErrorStatus(const SyncFileItem::Status & s) { _errorStatus = s; }
|
||||||
|
|
||||||
virtual void slotTimeout() Q_DECL_OVERRIDE;
|
virtual void slotTimeout() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
|||||||
@@ -85,9 +85,10 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||||||
<< (_job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : _job->reply()->errorString());
|
<< (_job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : _job->reply()->errorString());
|
||||||
|
|
||||||
QNetworkReply::NetworkError err = _job->reply()->error();
|
QNetworkReply::NetworkError err = _job->reply()->error();
|
||||||
_item._httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
const int httpStatus = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
_item._httpErrorCode = httpStatus;
|
||||||
|
|
||||||
if (err != QNetworkReply::NoError) {
|
if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
|
||||||
|
|
||||||
if( checkForProblemsWithShared(_item._httpErrorCode,
|
if( checkForProblemsWithShared(_item._httpErrorCode,
|
||||||
tr("The file has been removed from a read only share. It was restored.")) ) {
|
tr("The file has been removed from a read only share. It was restored.")) ) {
|
||||||
@@ -102,7 +103,11 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||||||
_item._requestDuration = _job->duration();
|
_item._requestDuration = _job->duration();
|
||||||
_item._responseTimeStamp = _job->responseTimestamp();
|
_item._responseTimeStamp = _job->responseTimestamp();
|
||||||
|
|
||||||
if (_item._httpErrorCode != 204 ) {
|
// A 404 reply is also considered a success here: We want to make sure
|
||||||
|
// a file is gone from the server. It not being there in the first place
|
||||||
|
// is ok. This will happen for files that are in the DB but not on
|
||||||
|
// the server or the local file system.
|
||||||
|
if (httpStatus != 204 && httpStatus != 404) {
|
||||||
// Normaly we expect "204 No Content"
|
// Normaly we expect "204 No Content"
|
||||||
// If it is not the case, it might be because of a proxy or gateway intercepting the request, so we must
|
// If it is not the case, it might be because of a proxy or gateway intercepting the request, so we must
|
||||||
// throw an error.
|
// throw an error.
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ static qint64 chunkSize() {
|
|||||||
return chunkSize;
|
return chunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUTFileJob::~PUTFileJob()
|
||||||
|
{
|
||||||
|
// Make sure that we destroy the QNetworkReply before our _device of which it keeps an internal pointer.
|
||||||
|
setReply(0);
|
||||||
|
}
|
||||||
|
|
||||||
void PUTFileJob::start() {
|
void PUTFileJob::start() {
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
||||||
@@ -518,8 +524,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
// But if the upload is ongoing, because not all chunks were uploaded
|
// But if the upload is ongoing, because not all chunks were uploaded
|
||||||
// yet, the upload can be stopped and an error can be displayed, because
|
// yet, the upload can be stopped and an error can be displayed, because
|
||||||
// the server hasn't registered the new file yet.
|
// the server hasn't registered the new file yet.
|
||||||
bool finished = job->reply()->hasRawHeader("ETag")
|
QByteArray etag = getEtagFromReply(job->reply());
|
||||||
|| job->reply()->hasRawHeader("OC-ETag");
|
bool finished = etag.length() > 0;
|
||||||
|
|
||||||
// Check if the file still exists
|
// Check if the file still exists
|
||||||
const QString fullFilePath(_propagator->getFilePath(_item._file));
|
const QString fullFilePath(_propagator->getFilePath(_item._file));
|
||||||
@@ -589,7 +595,6 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
_item._fileId = fid;
|
_item._fileId = fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray etag = getEtagFromReply(job->reply());
|
|
||||||
_item._etag = etag;
|
_item._etag = etag;
|
||||||
|
|
||||||
_item._responseTimeStamp = job->responseTimestamp();
|
_item._responseTimeStamp = job->responseTimestamp();
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public:
|
|||||||
explicit PUTFileJob(AccountPtr account, const QString& path, QIODevice *device,
|
explicit PUTFileJob(AccountPtr account, const QString& path, QIODevice *device,
|
||||||
const QMap<QByteArray, QByteArray> &headers, int chunk, QObject* parent = 0)
|
const QMap<QByteArray, QByteArray> &headers, int chunk, QObject* parent = 0)
|
||||||
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers), _chunk(chunk) {}
|
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers), _chunk(chunk) {}
|
||||||
|
~PUTFileJob();
|
||||||
|
|
||||||
int _chunk;
|
int _chunk;
|
||||||
|
|
||||||
|
|||||||
@@ -695,7 +695,8 @@ void PropagateDownloadFileLegacy::start()
|
|||||||
&& !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict.
|
&& !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict.
|
||||||
//In case of conflict, make a backup of the old file
|
//In case of conflict, make a backup of the old file
|
||||||
if (isConflict) {
|
if (isConflict) {
|
||||||
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime));
|
auto conflictDate = FileSystem::fileExists(fn) ? FileSystem::getModTime(fn) : _item._modtime;
|
||||||
|
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(conflictDate));
|
||||||
QString renameError;
|
QString renameError;
|
||||||
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
|
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
|
||||||
//If the rename fails, don't replace it.
|
//If the rename fails, don't replace it.
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
case CSYNC_STATUS_STORAGE_UNAVAILABLE:
|
case CSYNC_STATUS_STORAGE_UNAVAILABLE:
|
||||||
item._errorString = QLatin1String("Directory temporarily not available on server.");
|
item._errorString = QLatin1String("Directory temporarily not available on server.");
|
||||||
item._status = SyncFileItem::SoftError;
|
item._status = SyncFileItem::SoftError;
|
||||||
|
_temporarilyUnavailablePaths.insert(item._file);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Q_ASSERT("Non handled error-status");
|
Q_ASSERT("Non handled error-status");
|
||||||
@@ -484,9 +485,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
}
|
}
|
||||||
|
|
||||||
item._direction = dir;
|
item._direction = dir;
|
||||||
// check for blacklisting of this item.
|
if (instruction != CSYNC_INSTRUCTION_NONE) {
|
||||||
// if the item is on blacklist, the instruction was set to IGNORE
|
// check for blacklisting of this item.
|
||||||
checkErrorBlacklisting( &item );
|
// if the item is on blacklist, the instruction was set to ERROR
|
||||||
|
checkErrorBlacklisting( &item );
|
||||||
|
}
|
||||||
|
|
||||||
if (!item._isDirectory) {
|
if (!item._isDirectory) {
|
||||||
_progressInfo._totalFileCount++;
|
_progressInfo._totalFileCount++;
|
||||||
@@ -602,14 +605,25 @@ void SyncEngine::startSync()
|
|||||||
// database creation error!
|
// database creation error!
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileRecordCount >= 1 && isUpdateFrom_1_5) {
|
bool isUpdateFrom_1_8 = _journal->isUpdateFrom_1_8_0();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 1.8.0 caused missing data in the local tree, this patch gets it
|
||||||
|
* back. For that, the usage of the journal for remote repository is
|
||||||
|
* disabled at the first start.
|
||||||
|
*/
|
||||||
|
if (fileRecordCount >= 1 && (isUpdateFrom_1_5 || isUpdateFrom_1_8)) {
|
||||||
qDebug() << "detected update from 1.5" << fileRecordCount << isUpdateFrom_1_5;
|
qDebug() << "detected update from 1.5" << fileRecordCount << isUpdateFrom_1_5;
|
||||||
// Disable the read from DB to be sure to re-read all the fileid and etags.
|
// Disable the read from DB to be sure to re-read all the fileid and etags.
|
||||||
csync_set_read_from_db(_csync_ctx, false);
|
_csync_ctx->read_remote_from_db = false;
|
||||||
} else {
|
} else {
|
||||||
csync_set_read_from_db(_csync_ctx, true);
|
_csync_ctx->read_remote_from_db = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This tells csync to never read from the DB if it is empty
|
||||||
|
// thereby speeding up the initial discovery significantly.
|
||||||
|
_csync_ctx->db_is_empty = (fileRecordCount == 0);
|
||||||
|
|
||||||
bool usingSelectiveSync = (!_selectiveSyncBlackList.isEmpty());
|
bool usingSelectiveSync = (!_selectiveSyncBlackList.isEmpty());
|
||||||
qDebug() << (usingSelectiveSync ? "====Using Selective Sync" : "====NOT Using Selective Sync");
|
qDebug() << (usingSelectiveSync ? "====Using Selective Sync" : "====NOT Using Selective Sync");
|
||||||
if (fileRecordCount >= 0 && fileRecordCount < 50 && !usingSelectiveSync) {
|
if (fileRecordCount >= 0 && fileRecordCount < 50 && !usingSelectiveSync) {
|
||||||
@@ -690,7 +704,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
|
qDebug() << "<<#### Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
|
||||||
|
|
||||||
_progressInfo = Progress::Info();
|
_progressInfo = Progress::Info();
|
||||||
|
|
||||||
@@ -698,6 +712,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||||||
_hasRemoveFile = false;
|
_hasRemoveFile = false;
|
||||||
bool walkOk = true;
|
bool walkOk = true;
|
||||||
_seenFiles.clear();
|
_seenFiles.clear();
|
||||||
|
_temporarilyUnavailablePaths.clear();
|
||||||
|
|
||||||
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
||||||
qDebug() << "Error in local treewalk.";
|
qDebug() << "Error in local treewalk.";
|
||||||
@@ -791,6 +806,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||||||
emit(started());
|
emit(started());
|
||||||
|
|
||||||
_propagator->start(_syncedItems);
|
_propagator->start(_syncedItems);
|
||||||
|
|
||||||
|
qDebug() << "<<#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Post-Reconcile Finished"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncEngine::slotCleanPollsJobAborted(const QString &error)
|
void SyncEngine::slotCleanPollsJobAborted(const QString &error)
|
||||||
@@ -859,7 +876,7 @@ void SyncEngine::slotFinished()
|
|||||||
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
|
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
|
||||||
|
|
||||||
// emit the treewalk results.
|
// emit the treewalk results.
|
||||||
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
|
if( ! _journal->postSyncCleanup( _seenFiles, _temporarilyUnavailablePaths ) ) {
|
||||||
qDebug() << "Cleaning of synced ";
|
qDebug() << "Cleaning of synced ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,8 +1006,8 @@ void SyncEngine::checkForPermission()
|
|||||||
it->_direction = SyncFileItem::Down;
|
it->_direction = SyncFileItem::Down;
|
||||||
it->_isRestoration = true;
|
it->_isRestoration = true;
|
||||||
// take the things to write to the db from the "other" node (i.e: info from server)
|
// take the things to write to the db from the "other" node (i.e: info from server)
|
||||||
// ^^ FIXME This might not be needed anymore since we merge the info in treewalkFile
|
|
||||||
it->_modtime = it->log._other_modtime;
|
it->_modtime = it->log._other_modtime;
|
||||||
|
it->_size = it->log._other_size;
|
||||||
it->_fileId = it->log._other_fileId;
|
it->_fileId = it->log._other_fileId;
|
||||||
it->_etag = it->log._other_etag;
|
it->_etag = it->log._other_etag;
|
||||||
it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
|
it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
|
||||||
|
|||||||
@@ -159,7 +159,21 @@ private:
|
|||||||
QPointer<DiscoveryMainThread> _discoveryMainThread;
|
QPointer<DiscoveryMainThread> _discoveryMainThread;
|
||||||
QSharedPointer <OwncloudPropagator> _propagator;
|
QSharedPointer <OwncloudPropagator> _propagator;
|
||||||
QString _lastDeleted; // if the last item was a path and it has been deleted
|
QString _lastDeleted; // if the last item was a path and it has been deleted
|
||||||
|
|
||||||
|
// After a sync, only the syncdb entries whose filenames appear in this
|
||||||
|
// set will be kept. See _temporarilyUnavailablePaths.
|
||||||
QSet<QString> _seenFiles;
|
QSet<QString> _seenFiles;
|
||||||
|
|
||||||
|
// Some paths might be temporarily unavailable on the server, for
|
||||||
|
// example due to 503 Storage not available. Deleting information
|
||||||
|
// about the files from the database in these cases would lead to
|
||||||
|
// incorrect synchronization.
|
||||||
|
// Therefore all syncdb entries whose filename starts with one of
|
||||||
|
// the paths in this set will be kept.
|
||||||
|
// The specific case that fails otherwise is deleting a local file
|
||||||
|
// while the remote says storage not available.
|
||||||
|
QSet<QString> _temporarilyUnavailablePaths;
|
||||||
|
|
||||||
QThread _thread;
|
QThread _thread;
|
||||||
|
|
||||||
Progress::Info _progressInfo;
|
Progress::Info _progressInfo;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
||||||
QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false)
|
QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false), _possibleUpgradeFromMirall_1_8_0(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
_dbFile = path;
|
_dbFile = path;
|
||||||
@@ -273,6 +273,8 @@ bool SyncJournalDb::checkConnect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_possibleUpgradeFromMirall_1_5 = false;
|
_possibleUpgradeFromMirall_1_5 = false;
|
||||||
|
_possibleUpgradeFromMirall_1_8_0 = false;
|
||||||
|
|
||||||
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
|
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
|
||||||
if (!versionQuery.next()) {
|
if (!versionQuery.next()) {
|
||||||
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
||||||
@@ -284,7 +286,7 @@ bool SyncJournalDb::checkConnect()
|
|||||||
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
||||||
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
||||||
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
||||||
createQuery.bindValue(3, MIRALL_VERSION_BUILD);
|
createQuery.bindValue(4, MIRALL_VERSION_BUILD);
|
||||||
createQuery.exec();
|
createQuery.exec();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -292,6 +294,10 @@ bool SyncJournalDb::checkConnect()
|
|||||||
int minor = versionQuery.intValue(1);
|
int minor = versionQuery.intValue(1);
|
||||||
int patch = versionQuery.intValue(2);
|
int patch = versionQuery.intValue(2);
|
||||||
|
|
||||||
|
if( major == 1 && minor == 8 && patch == 0 ) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "_possibleUpgradeFromMirall_1_8_0 detected!";
|
||||||
|
_possibleUpgradeFromMirall_1_8_0 = true;
|
||||||
|
}
|
||||||
// Not comparing the BUILD id here, correct?
|
// Not comparing the BUILD id here, correct?
|
||||||
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
|
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
|
||||||
createQuery.prepare("UPDATE version SET major=?1, minor=?2, patch =?3, custom=?4 "
|
createQuery.prepare("UPDATE version SET major=?1, minor=?2, patch =?3, custom=?4 "
|
||||||
@@ -698,7 +704,8 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
|
|||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
bool SyncJournalDb::postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
||||||
|
const QSet<QString>& prefixesToKeep)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
|
|
||||||
@@ -719,8 +726,16 @@ bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
|||||||
|
|
||||||
while(query.next()) {
|
while(query.next()) {
|
||||||
const QString file = query.stringValue(1);
|
const QString file = query.stringValue(1);
|
||||||
bool contained = items.contains(file);
|
bool keep = filepathsToKeep.contains(file);
|
||||||
if( !contained ) {
|
if( !keep ) {
|
||||||
|
foreach( const QString & prefix, prefixesToKeep ) {
|
||||||
|
if( file.startsWith(prefix) ) {
|
||||||
|
keep = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !keep ) {
|
||||||
superfluousItems.append(query.stringValue(0));
|
superfluousItems.append(query.stringValue(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,6 +759,10 @@ bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
|||||||
_possibleUpgradeFromMirall_1_5 = false; // should be handled now
|
_possibleUpgradeFromMirall_1_5 = false; // should be handled now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_possibleUpgradeFromMirall_1_8_0) {
|
||||||
|
_possibleUpgradeFromMirall_1_8_0 = false; // should be handled now
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1313,6 +1332,13 @@ bool SyncJournalDb::isUpdateFrom_1_5()
|
|||||||
return _possibleUpgradeFromMirall_1_5;
|
return _possibleUpgradeFromMirall_1_5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SyncJournalDb::isUpdateFrom_1_8_0()
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&_mutex);
|
||||||
|
checkConnect();
|
||||||
|
return _possibleUpgradeFromMirall_1_8_0;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
|
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
|
||||||
const SyncJournalDb::DownloadInfo & rhs)
|
const SyncJournalDb::DownloadInfo & rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void avoidReadFromDbOnNextSync(const QString& fileName);
|
void avoidReadFromDbOnNextSync(const QString& fileName);
|
||||||
|
|
||||||
bool postSyncCleanup( const QSet<QString>& items );
|
bool postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
||||||
|
const QSet<QString>& prefixesToKeep);
|
||||||
|
|
||||||
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions
|
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions
|
||||||
* Commit will actually commit the transaction and create a new one.
|
* Commit will actually commit the transaction and create a new one.
|
||||||
@@ -117,6 +118,7 @@ public:
|
|||||||
* are updated.
|
* are updated.
|
||||||
*/
|
*/
|
||||||
bool isUpdateFrom_1_5();
|
bool isUpdateFrom_1_5();
|
||||||
|
bool isUpdateFrom_1_8_0();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool updateDatabaseStructure();
|
bool updateDatabaseStructure();
|
||||||
@@ -134,6 +136,7 @@ private:
|
|||||||
QMutex _mutex; // Public functions are protected with the mutex.
|
QMutex _mutex; // Public functions are protected with the mutex.
|
||||||
int _transaction;
|
int _transaction;
|
||||||
bool _possibleUpgradeFromMirall_1_5;
|
bool _possibleUpgradeFromMirall_1_5;
|
||||||
|
bool _possibleUpgradeFromMirall_1_8_0;
|
||||||
QScopedPointer<SqlQuery> _getFileRecordQuery;
|
QScopedPointer<SqlQuery> _getFileRecordQuery;
|
||||||
QScopedPointer<SqlQuery> _setFileRecordQuery;
|
QScopedPointer<SqlQuery> _setFileRecordQuery;
|
||||||
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
|
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
|
||||||
|
|||||||
@@ -122,11 +122,14 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
|
|||||||
flavor = QLatin1String("colored");
|
flavor = QLatin1String("colored");
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon icon;
|
|
||||||
if( QIcon::hasThemeIcon( name )) {
|
if( QIcon::hasThemeIcon( name )) {
|
||||||
// use from theme
|
// use from theme
|
||||||
icon = QIcon::fromTheme( name );
|
return QIcon::fromTheme( name );
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
QString key = name + "," + flavor;
|
||||||
|
QIcon & cached = _iconCache[key];
|
||||||
|
if (cached.isNull()) {
|
||||||
QList<int> sizes;
|
QList<int> sizes;
|
||||||
sizes <<16 << 22 << 32 << 48 << 64 << 128 << 256;
|
sizes <<16 << 22 << 32 << 48 << 64 << 128 << 256;
|
||||||
foreach (int size, sizes) {
|
foreach (int size, sizes) {
|
||||||
@@ -140,19 +143,20 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
|
|||||||
p.setPen(QColor("#dfdbd2"));
|
p.setPen(QColor("#dfdbd2"));
|
||||||
p.drawPixmap(px.rect(), mask, mask.rect());
|
p.drawPixmap(px.rect(), mask, mask.rect());
|
||||||
}
|
}
|
||||||
icon.addPixmap(px);
|
cached.addPixmap(px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (icon.isNull()) {
|
if (cached.isNull()) {
|
||||||
foreach (int size, sizes) {
|
foreach (int size, sizes) {
|
||||||
QString pixmapName = QString::fromLatin1(":/client/resources/%1-%2.png").arg(name).arg(size);
|
QString pixmapName = QString::fromLatin1(":/client/resources/%1-%2.png").arg(name).arg(size);
|
||||||
if (QFile::exists(pixmapName)) {
|
if (QFile::exists(pixmapName)) {
|
||||||
icon.addFile(pixmapName);
|
cached.addFile(pixmapName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return icon;
|
|
||||||
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
|
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#ifndef _THEME_H
|
#ifndef _THEME_H
|
||||||
#define _THEME_H
|
#define _THEME_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include "syncresult.h"
|
#include "syncresult.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -196,7 +197,9 @@ public:
|
|||||||
virtual bool wizardSelectiveSyncDefaultNothing() const;
|
virtual bool wizardSelectiveSyncDefaultNothing() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
QIcon themeIcon(const QString& name, bool sysTray = false) const;
|
QIcon themeIcon(const QString& name, bool sysTray = false) const;
|
||||||
|
#endif
|
||||||
Theme();
|
Theme();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -208,7 +211,9 @@ private:
|
|||||||
|
|
||||||
static Theme* _instance;
|
static Theme* _instance;
|
||||||
bool _mono;
|
bool _mono;
|
||||||
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
|
mutable QHash<QString, QIcon> _iconCache;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ owncloud_add_test(SyncJournalDB "")
|
|||||||
owncloud_add_test(SyncFileItem "")
|
owncloud_add_test(SyncFileItem "")
|
||||||
owncloud_add_test(ConcatUrl "")
|
owncloud_add_test(ConcatUrl "")
|
||||||
|
|
||||||
|
owncloud_add_test(XmlParse "")
|
||||||
|
|
||||||
|
|||||||
245
test/testxmlparse.h
Normal file
245
test/testxmlparse.h
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* This software is in the public domain, furnished "as is", without technical
|
||||||
|
* support, and with no warranty, express or implied, as to its usefulness for
|
||||||
|
* any purpose.
|
||||||
|
* */
|
||||||
|
|
||||||
|
#ifndef MIRALL_TESTXMLPARSE_H
|
||||||
|
#define MIRALL_TESTXMLPARSE_H
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include "networkjobs.h"
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
|
||||||
|
class TestXmlParse : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _success;
|
||||||
|
QStringList _subdirs;
|
||||||
|
QStringList _items;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotDirectoryListingSubFolders(const QStringList& list)
|
||||||
|
{
|
||||||
|
qDebug() << "subfolders: " << list;
|
||||||
|
_subdirs.append(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotDirectoryListingIterated(const QString& item, const QMap<QString,QString>& )
|
||||||
|
{
|
||||||
|
qDebug() << " item: " << item;
|
||||||
|
_items.append(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotFinishedSuccessfully()
|
||||||
|
{
|
||||||
|
_success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void init() {
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
_success = false;
|
||||||
|
_subdirs.clear();
|
||||||
|
_items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void testParser1() {
|
||||||
|
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
|
||||||
|
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||||
|
"<oc:size>121780</oc:size>"
|
||||||
|
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||||
|
"<d:resourcetype>"
|
||||||
|
"<d:collection/>"
|
||||||
|
"</d:resourcetype>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<d:getcontentlength/>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVW</oc:permissions>"
|
||||||
|
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||||
|
"<d:resourcetype/>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"</d:multistatus>";
|
||||||
|
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(parser.parse( testXml, &sizes ));
|
||||||
|
|
||||||
|
QVERIFY(_success);
|
||||||
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
|
|
||||||
|
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder/quitte.pdf"));
|
||||||
|
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder"));
|
||||||
|
QVERIFY(_items.size() == 2 );
|
||||||
|
|
||||||
|
QVERIFY(_subdirs.contains("/oc/remote.php/webdav/sharefolder/"));
|
||||||
|
QVERIFY(_subdirs.size() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testParserBrokenXml() {
|
||||||
|
const QByteArray testXml = "X<?xml version='1.0' encoding='utf-8'?>"
|
||||||
|
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||||
|
"<oc:size>121780</oc:size>"
|
||||||
|
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||||
|
"<d:resourcetype>"
|
||||||
|
"<d:collection/>"
|
||||||
|
"</d:resourcetype>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<d:getcontentlength/>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVW</oc:permissions>"
|
||||||
|
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||||
|
"<d:resourcetype/>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"</d:multistatus>";
|
||||||
|
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||||
|
|
||||||
|
QVERIFY(!_success);
|
||||||
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
|
|
||||||
|
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||||
|
|
||||||
|
QVERIFY(_subdirs.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testParserEmptyXmlNoDav() {
|
||||||
|
const QByteArray testXml = "<html><body>I am under construction</body></html>";
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||||
|
|
||||||
|
QVERIFY(!_success);
|
||||||
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
|
|
||||||
|
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||||
|
QVERIFY(_subdirs.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testParserEmptyXml() {
|
||||||
|
const QByteArray testXml = "";
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||||
|
|
||||||
|
QVERIFY(!_success);
|
||||||
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
|
|
||||||
|
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||||
|
QVERIFY(_subdirs.size() == 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,6 +22,7 @@ trans.pt_BR = client_pt_BR.ts
|
|||||||
trans.ru = client_ru.ts
|
trans.ru = client_ru.ts
|
||||||
trans.sl = client_sl.ts
|
trans.sl = client_sl.ts
|
||||||
trans.sv = client_sv.ts
|
trans.sv = client_sv.ts
|
||||||
|
trans.sr = client_sr.ts
|
||||||
trans.tr = client_tr.ts
|
trans.tr = client_tr.ts
|
||||||
trans.uk = client_uk.ts
|
trans.uk = client_uk.ts
|
||||||
trans.zh_TW = client_zh_TW.ts
|
trans.zh_TW = client_zh_TW.ts
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user