1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2025-04-09 19:15:43 +02:00

Merge branch 'master' of github.com:nextcloud/client

This commit is contained in:
István Váradi 2018-06-05 06:58:12 +02:00
commit d0e4c67459
132 changed files with 52382 additions and 1897 deletions
.tx/nextcloud.client-desktop
CMakeLists.txtVERSION.cmake
admin/osx
cmake/modules
config.h.in
doc
shell_integration
src

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[cs_CZ]=@APPLICATION_NAME@ desktopový synchronizační klient
Icon[cs_CZ]=@APPLICATION_EXECUTABLE@
Name[cs_CZ]=@APPLICATION_NAME@ desktopový synchronizační klient
GenericName[cs_CZ]=Synchronizace složek

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
Icon[de]=@APPLICATION_EXECUTABLE@
Name[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
GenericName[de]=Synchronisationsordner

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
Icon[en_GB]=@APPLICATION_EXECUTABLE@
Name[en_GB]=@APPLICATION_NAME@ desktop sync client
GenericName[en_GB]=Folder Sync

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_CL]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_CL]=@APPLICATION_EXECUTABLE@
Name[es_CL]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_CL]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_CO]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_CO]=@APPLICATION_EXECUTABLE@
Name[es_CO]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_CO]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_CR]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_CR]=@APPLICATION_EXECUTABLE@
Name[es_CR]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_CR]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_DO]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_DO]=@APPLICATION_EXECUTABLE@
Name[es_DO]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_DO]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_EC]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_EC]=@APPLICATION_EXECUTABLE@
Name[es_EC]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_EC]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_GT]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_GT]=@APPLICATION_EXECUTABLE@
Name[es_GT]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_GT]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_MX]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_MX]=@APPLICATION_EXECUTABLE@
Name[es_MX]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_MX]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es_SV]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
Icon[es_SV]=@APPLICATION_EXECUTABLE@
Name[es_SV]=@APPLICATION_NAME@ Cliente de sincronización de escritorio
GenericName[es_SV]=Sincronización de carpeta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[es]=Cliente de sincronización de escritorio @APPLICATION_NAME@
Icon[es]=@APPLICATION_EXECUTABLE@
Name[es]=Cliente de sincronización de escritorio @APPLICATION_NAME@
GenericName[es]=Sincronización de carpetas

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[fr]=Client desktop de synchronisation @APPLICATION_NAME@
Icon[fr]=@APPLICATION_EXECUTABLE@
Name[fr]=Client desktop de synchronisation @APPLICATION_NAME@
GenericName[fr]=Synchronisation du dossier

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[he]=@APPLICATION_NAME@ לקוח סנכרון לשולחן העבודה
Icon[he]=@APPLICATION_EXECUTABLE@
Name[he]=@APPLICATION_NAME@ לקוח סנכרון לשולחן העבודה
GenericName[he]=סנכרון תיקיות

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[is]=@APPLICATION_NAME@ forrit til samstillingar við tölvu
Icon[is]=@APPLICATION_EXECUTABLE@
Name[is]=@APPLICATION_NAME@ forrit til samstillingar við tölvu
GenericName[is]=Samstilling á möppum

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[it]=Client di sincronizzazione desktop di @APPLICATION_NAME@
Icon[it]=@APPLICATION_EXECUTABLE@
Name[it]=Client di sincronizzazione desktop di @APPLICATION_NAME@
GenericName[it]=Sincronizzazione cartelle

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização desktop
Icon[pt_BR]=@APPLICATION_EXECUTABLE@
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização desktop
GenericName[pt_BR]=Sincronizar Pasta

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[ru]=Клиент синхронизации @APPLICATION_NAME@ для ПК
Icon[ru]=@APPLICATION_EXECUTABLE@
Name[ru]=@APPLICATION_NAME@ клиент для ПК
GenericName[ru]=Синхронизация папок

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[sr]=@APPLICATION_NAME@ десктоп клијент за синхронизацију
Icon[sr]=@APPLICATION_EXECUTABLE@
Name[sr]=@APPLICATION_NAME@ десктоп клијент за синхронизацију
GenericName[sr]=Синхронизација фасцикли

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[tr]=@APPLICATION_NAME@ masaüstü eşitleme istemcisi
Icon[tr]=@APPLICATION_EXECUTABLE@
Name[tr]=@APPLICATION_NAME@ masaüstü eşiteme istemcisi
GenericName[tr]=Klasör Eşitleme

View File

@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[zh_TW]=@APPLICATION_NAME@ 桌面同步客戶端
Icon[zh_TW]=@APPLICATION_EXECUTABLE@
Name[zh_TW]=@APPLICATION_NAME@ 桌面同步客戶端
GenericName[zh_TW]=資料夾同步

View File

@ -215,9 +215,6 @@ endif()
file( GLOB TRANS_FILES ${CMAKE_SOURCE_DIR}/translations/client_*.ts)
set(TRANSLATIONS ${TRANS_FILES})
# Make sure we set this before recursing into child folders.
set(WITH_TESTING ${UNIT_TESTING})
if(BUILD_CLIENT)
add_subdirectory(src)
if(NOT BUILD_LIBRARIES_ONLY)

View File

@ -1,7 +1,7 @@
set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 5 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_VERSION_YEAR 2017 )
set( MIRALL_VERSION_YEAR 2018 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )

View File

@ -337,6 +337,13 @@ for binary in binaries:
for plugin in QT_PLUGINS:
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.10.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
commands.append(args)
else:
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.7.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
commands.append(args)
if len(sys.argv) <= 2:
print 'Will run %d commands:' % len(commands)
for command in commands:

View File

@ -1,12 +1,16 @@
#!/bin/sh
osascript << EOF
# Check if Finder is running (for systems with Finder disabled)
finder_status=`ps aux | grep "/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder" | grep -v "grep"`
if ! [ "$finder_status" == "" ] ; then # Finder is running
osascript << EOF
tell application "Finder"
activate
select the last Finder window
reveal POSIX file "/Applications/@APPLICATION_EXECUTABLE@.app"
end tell
EOF
fi
# Always enable the new 10.10 finder plugin if available
if [ -x "$(command -v pluginkit)" ]; then

View File

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

View File

@ -24,6 +24,4 @@
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
#cmakedefine SHAREDIR "@SHAREDIR@"
#cmakedefine WITH_TESTING 1
#endif

View File

@ -250,9 +250,14 @@ Some system wide file patterns that are used to exclude or ignore files are incl
By default, the Nextcloud Client ignores the following files:
* Files matched by one of the patterns defined in the Ignored Files Editor
* Files containing characters that do not work on certain file systems ``(`\, /, :, ?, *, ", >, <, |`)``.
* Files starting with ``._sync_xxxxxxx.db`` and the old format ``.csync_journal.db``, as these files are reserved for journalling.
* Files matched by one of the patterns defined in the Ignored Files Editor.
* Files starting with ``._sync_*.db*``, ``.sync_*.db*``, ``.csync_journal.db*``, ``.owncloudsync.log*``, as these files are reserved for journalling.
* Files with a name longer than 254 characters.
* The file ``Desktop.ini`` in the root of a synced folder.
* Files matching the pattern ``*_conflict-*`` unless conflict file uploading is enabled.
* Windows only: Files containing characters that do not work on typical Windows filesystems ``(`\, /, :, ?, *, ", >, <, |`)``.
* Windows only: Files with a trailing space or dot.
* Windows only: Filenames that are reserved on Windows.
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
a line in the exclude file starts with the character ``]`` directly followed by

View File

@ -2,18 +2,18 @@
The Automatic Updater
=====================
The Automatic Updater ensures that you always have the
The Automatic Updater ensures that you always have the
latest features and bug fixes for your Nextcloud synchronization client.
The Automatic Updater updates only on Mac OS X and Windows computers; Linux
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 Automatic Updater updates only on macOS and Windows computers; Linux
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
available.
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.
Windows
@ -29,20 +29,20 @@ itself. Should the silent update fail, the client offers a manual download.
.. note:: Administrative privileges are required to perform the update.
Mac OS X
^^^^^^^^
macOS
^^^^^
If a new update is available, the Nextcloud client initializes a pop-up dialog
to alert you of the update and requesting that you update to the latest
version. Due to their use of the Sparkle frameworks, this is the default
process for Mac OS X applications.
process for macOS applications.
Linux
^^^^^
Linux distributions provide their own update tools, so Nextcloud clients that use
the Linux operating system do not perform any updates on their own. The client
will inform you (``Settings -> General -> Updates``) when an update is
the Linux operating system do not perform any updates on their own. The client
will inform you (``Settings -> General -> Updates``) when an update is
available.
Preventing Automatic Updates
@ -57,14 +57,14 @@ auto-update mechanism for different operating systems.
Preventing Automatic Updates in Windows Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Users may disable automatic updates by adding this line to the [General]
Users may disable automatic updates by adding this line to the [General]
section of their ``nextcloud.cfg`` files::
skipUpdateCheck=true
Windows administrators have more options for preventing automatic updates in
Windows environments by using one of two methods. The first method allows users
to override the automatic update check mechanism, whereas the second method
Windows administrators have more options for preventing automatic updates in
Windows environments by using one of two methods. The first method allows users
to override the automatic update check mechanism, whereas the second method
prevents any manual overrides.
To prevent automatic updates, but allow manual overrides:
@ -82,7 +82,7 @@ To manually override this key, use the same value in ``HKEY_CURRENT_USER``.
To prevent automatic updates and disallow manual overrides:
.. note:: This is the preferred method of controlling the updater behavior using
.. note:: This is the preferred method of controlling the updater behavior using
Group Policies.
1. Edit this Registry key:
@ -96,10 +96,10 @@ To prevent automatic updates and disallow manual overrides:
.. note:: branded clients have different key names
Preventing Automatic Updates in Mac OS X Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Preventing Automatic Updates in macOS Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can disable the automatic update mechanism, in the Mac OS X operating system,
You can disable the automatic update mechanism, in the macOS operating system,
by copying the file
``nextcloud.app/Contents/Resources/deny_autoupdate_com.nextcloud.desktopclient.plist``
to ``/Library/Preferences/com.nextcloud.desktopclient.plist``.

View File

@ -16,14 +16,14 @@ These instructions are updated to work with version |version| of the Nextcloud C
Getting Source Code
-------------------
The :ref:`generic-build-instructions` pull the latest code directly from
GitHub, and work on Linux, Mac OS X, and Windows.
The :ref:`generic-build-instructions` pull the latest code directly from
GitHub, and work on Linux, macOS, and Windows.
Mac OS X
--------
macOS
-----
In addition to needing XCode (along with the command line tools), developing in
the Mac OS X environment requires extra dependencies. You can install these
the macOS environment requires extra dependencies. You can install these
dependencies through MacPorts_ or Homebrew_. These dependencies are required
only on the build machine, because non-standard libs are deployed in the app
bundle.
@ -60,14 +60,14 @@ To set up your build environment for development using HomeBrew_:
Where ``x.y`` is the current version of Qt 5 that brew has installed
on your machine.
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
make sure you make the same install prefix as later while building the client e.g. -
make sure you make the same install prefix as later while building the client e.g. -
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
10. Install the Packages_ package creation tool.
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir> <install_dir>``.
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir> <install_dir>``.
If you have a developer signing certificate, you can specify
its Common Name as a third parameter (use quotes) to have the package
signed automatically.
@ -137,7 +137,7 @@ is **currently only officially supported on openSUSE**, by using the MinGW cross
You can set up any currently supported version of openSUSE in a virtual machine if you do not
have it installed already.
In order to make setup simple, you can use the provided Dockerfile to build your own image.
In order to make setup simple, you can use the provided Dockerfile to build your own image.
1. Assuming you are in the root of the Nextcloud Client's source tree, you can
build an image from this Dockerfile like this::
@ -209,24 +209,24 @@ To build the most up-to-date version of the client:
3. Configure the client build::
cmake -DCMAKE_BUILD_TYPE="Debug" ..
.. note:: You must use absolute paths for the ``include`` and ``library``
directories.
.. note:: On Mac OS X, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
.. note:: On macOS, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
where ``target`` is a private location, i.e. in parallel to your build
dir by specifying ``../install``.
.. note:: qtkeychain must be compiled with the same prefix e.g ``CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ .``
.. note:: Example:: ``cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -DNO_SHIBBOLETH=1``
4. Call ``make``.
The Nextcloud binary will appear in the ``bin`` directory.
5. (Optional) Call ``make install`` to install the client to the
``/usr/local/bin`` directory.
5. (Optional) Call ``make install`` to install the client to the
``/usr/local/bin`` directory.
The following are known cmake parameters:

View File

@ -6,7 +6,7 @@ On Linux distributions:
On Microsoft Windows systems:
``%APPDATA%\Nextcloud\nextcloud.cfg``
On MAC OS X systems:
On macOS systems:
``$HOME/Library/Preferences/Nextcloud/nextcloud.cfg``

View File

@ -7,7 +7,7 @@ Glossary
Nextcloud Sync Client
Nextcloud Client
Name of the official Nextcloud syncing client for desktop, which runs on
Windows, Mac OS X and Linux. It uses the CSync sync engine for
Windows, macOS and Linux. It uses the CSync sync engine for
synchronization with the Nextcloud server.
Nextcloud Server

View File

@ -2,69 +2,69 @@
Installing the Desktop Synchronization Client
=============================================
You can download the latest version of the Nextcloud Desktop Synchronization
Client from the `Nextcloud download page`_.
There are clients for Linux, Mac OS X, and Microsoft Windows.
You can download the latest version of the Nextcloud Desktop Synchronization
Client from the `Nextcloud download page`_.
There are clients for Linux, macOS, and Microsoft Windows.
Installation on Mac OS X and Windows is the same as for any software
application: download the program and then double-click it to launch the
installation, and then follow the installation wizard. After it is installed and
configured the sync client will automatically keep itself updated; see
Installation on macOS and Windows is the same as for any software
application: download the program and then double-click it to launch the
installation, and then follow the installation wizard. After it is installed and
configured the sync client will automatically keep itself updated; see
:doc:`autoupdate` for more information.
Linux users must follow the instructions on the download page to add the
appropriate repository for their Linux distribution, install the signing key,
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
will display a notification when an update is available.
Linux users must follow the instructions on the download page to add the
appropriate repository for their Linux distribution, install the signing key,
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
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.
You will also find links to source code archives and older versions on the
You will also find links to source code archives and older versions on the
download page.
System Requirements
----------------------------------
- Windows 7+
- Mac OS X 10.7+ (**64-bit only**)
- macOS 10.7+ (**64-bit only**)
Installation Wizard
-------------------
The installation wizard takes you step-by-step through configuration options and
The installation wizard takes you step-by-step through configuration options and
account setup. First you need to enter the URL of your Nextcloud server.
.. image:: images/client-1.png
:alt: form for entering Nextcloud server URL
Enter your Nextcloud login on the next screen.
.. image:: images/client-2.png
:alt: form for entering your Nextcloud login
On the Local Folder Option screen you may sync
all of your files on the Nextcloud server, or select individual folders. The
default local sync folder is ``Nextcloud``, in your home directory. You may
On the Local Folder Option screen you may sync
all of your files on the Nextcloud server, or select individual folders. The
default local sync folder is ``Nextcloud``, in your home directory. You may
change this as well.
.. image:: images/client-3.png
:alt: Select which remote folders to sync, and which local folder to store
:alt: Select which remote folders to sync, and which local folder to store
them in.
When you have completed selecting your sync folders, click the Connect button
at the bottom right. The client will attempt to connect to your Nextcloud
server, and when it is successful you'll see two buttons: one to connect to
your Nextcloud Web GUI, and one to open your local folder. It will also start
When you have completed selecting your sync folders, click the Connect button
at the bottom right. The client will attempt to connect to your Nextcloud
server, and when it is successful you'll see two buttons: one to connect to
your Nextcloud Web GUI, and one to open your local folder. It will also start
synchronizing your files.
.. image:: images/client-4.png
:alt: A successful server connection, showing a button to connect to your
:alt: A successful server connection, showing a button to connect to your
Web GUI, and one to open your local Nextcloud folder
Click the Finish button, and you're all done.
Click the Finish button, and you're all done.
.. Links
.. _Nextcloud download page: https://nextcloud.com/download/#install-clients

View File

@ -2,27 +2,26 @@
Introduction
============
Available for Windows, Mac OS X, and various Linux distributions, the Nextcloud
Available for Windows, macOS, and various Linux distributions, the Nextcloud
Desktop Sync client enables you to:
- Specify one or more directories on your computer that you want to synchronize
to the Nextcloud server.
- Always have the latest files synchronized, wherever they are located.
Your files are always automatically synchronized between your Nextcloud server
Your files are always automatically synchronized between your Nextcloud server
and local PC.
Improvements and New Features
-----------------------------
The |version| release of the Nextcloud desktop sync client has many new features and
The |version| release of the Nextcloud desktop sync client has many new features and
improvements.
* Show server notifications on the client
* Improved sync speed
* Improved handling of Win32 file locks and network files
* Improved handling of Win32 file locks and network files
* Improved user notifications about ignored files and conflicts
* Add warnings for old server versions
* Update of QtKeyChain to support Windows credential store
* Packaging of dolphin overlay icon module for bleeding edge distributions

View File

@ -4,15 +4,15 @@ Using the Synchronization Client
.. index:: navigating, usage
The Nextcloud Desktop Client remains in the background and is visible as an icon
in the system tray (Windows, KDE), status bar (Mac OS X), or notification area
The Nextcloud Desktop Client remains in the background and is visible as an icon
in the system tray (Windows, KDE), status bar (macOS), or notification area
(Linux).
.. figure:: images/icon.png
:alt: Status icon, green circle and white checkmark
:alt: Status icon, green circle and white checkmark
The status indicator uses icons to indicate the current status of your
synchronization. The green circle with the white checkmark tells you that your
The status indicator uses icons to indicate the current status of your
synchronization. The green circle with the white checkmark tells you that your
synchronization is current and you are connected to your Nextcloud server.
.. figure:: images/icon-syncing.png
@ -21,35 +21,35 @@ synchronization is current and you are connected to your Nextcloud server.
The blue icon with the white semi-circles means synchronization is in progress.
.. figure:: images/icon-paused.png
:alt: Status icon, yellow circle and vertical parallel
:alt: Status icon, yellow circle and vertical parallel
lines
The yellow icon with the parallel lines tells you your synchronization
The yellow icon with the parallel lines tells you your synchronization
has been paused. (Most likely by you.)
.. figure:: images/icon-offline.png
:alt: Status icon, gray circle and three horizontal
:alt: Status icon, gray circle and three horizontal
white dots
The gray icon with three white dots means your sync client has lost its
The gray icon with three white dots means your sync client has lost its
connection with your Nextcloud server.
.. figure:: images/icon-information.png
:alt: Status icon, sign "!" in yellow circle
When you see a yellow circle with the sign "!" that is the informational icon,
When you see a yellow circle with the sign "!" that is the informational icon,
so you should click it to see what it has to tell you.
.. figure:: images/icon-error.png
:alt: Status icon, red circle and white x
The red circle with the white "x" indicates a configuration error, such as an
The red circle with the white "x" indicates a configuration error, such as an
incorrect login or server URL.
Systray Icon
------------
A right-click on the systray icon opens a menu for quick access to multiple
A right-click on the systray icon opens a menu for quick access to multiple
operations.
.. figure:: images/menu.png
@ -66,7 +66,7 @@ This menu provides the following options:
* An option to log in or log out of all of your accounts at once
* Quit Nextcloud, logging out and closing the client
A left-click on your systray icon opens the desktop client to the account
A left-click on your systray icon opens the desktop client to the account
settings window.
.. figure:: images/client-6.png
@ -77,151 +77,151 @@ Configuring Nextcloud Account Settings
.. index:: account settings, user, password, Server URL
At the top of the window are tabs for each configured sync account, and three
others for Activity, General and Network settings. On your account tabs you
At the top of the window are tabs for each configured sync account, and three
others for Activity, General and Network settings. On your account tabs you
have the following features:
* Connection status, showing which Nextcloud server you are connected to, and
* Connection status, showing which Nextcloud server you are connected to, and
your Nextcloud username.
* An **Account** button, which contains a dropdown menu with **Add New**,
* An **Account** button, which contains a dropdown menu with **Add New**,
**Log Out**, and **Remove**.
* Used and available space on the server.
* Current synchronization status.
* **Add Folder Sync Connection** button.
The little button with three dots (the overflow menu) that sits to the right of
The little button with three dots (the overflow menu) that sits to the right of
the sync status bar offers four additional options:
* Open Folder
* Choose What to Sync (This appears only when your file tree is collapsed, and
* Choose What to Sync (This appears only when your file tree is collapsed, and
expands the file tree)
* Pause Sync / Resume Sync
* Remove folder sync connection
**Open Folder** opens your local Nextcloud sync folder.
**Pause Sync** pauses sync operations without making any changes to your
account. It will continue to update file and folder lists, without
downloading or updating files. To stop all sync activity use **Remove
**Pause Sync** pauses sync operations without making any changes to your
account. It will continue to update file and folder lists, without
downloading or updating files. To stop all sync activity use **Remove
Folder Sync Connection**.
.. figure:: images/client-7.png
:alt: Extra options for sync operations
.. note:: Nextcloud does not preserve the mtime (modification time) of
directories, though it does update the mtimes on files. See
`Wrong folder date when syncing
<https://github.com/owncloud/core/issues/7009>`_ for discussion of this.
.. note:: Nextcloud does not preserve the mtime (modification time) of
directories, though it does update the mtimes on files. See
`Wrong folder date when syncing
<https://github.com/owncloud/core/issues/7009>`_ for discussion of this.
Adding New Accounts
^^^^^^^^^^^^^^^^^^^
You may configure multiple Nextcloud accounts in your desktop sync client. Simply
click the **Account** > **Add New** button on any account tab to add a new
account, and then follow the account creation wizard. The new account will
appear as a new tab in the settings dialog, where you can adjust its settings at
any time. Use **Account** > **Remove** to delete accounts.
You may configure multiple Nextcloud accounts in your desktop sync client. Simply
click the **Account** > **Add New** button on any account tab to add a new
account, and then follow the account creation wizard. The new account will
appear as a new tab in the settings dialog, where you can adjust its settings at
any time. Use **Account** > **Remove** to delete accounts.
File Manager Overlay Icons
--------------------------
The Nextcloud sync client provides overlay icons, in addition to the normal file
type icons, for your system file manager (Explorer on Windows, Finder on Mac and
The Nextcloud sync client provides overlay icons, in addition to the normal file
type icons, for your system file manager (Explorer on Windows, Finder on Mac and
Nautilus on Linux) to indicate the sync status of your Nextcloud files.
The overlay icons are similar to the systray icons introduced above. They
behave differently on files and directories according to sync status
and errors.
The overlay icons are similar to the systray icons introduced above. They
behave differently on files and directories according to sync status
and errors.
The overlay icon of an individual file indicates its current sync state. If the
file is in sync with the server version, it displays a green checkmark.
If the file is ignored from syncing, for example because it is on your
If the file is ignored from syncing, for example because it is on your
exclude list, or because it is a symbolic link, it displays a warning icon.
If there is a sync error, or the file is blacklisted, it displays an
If there is a sync error, or the file is blacklisted, it displays an
eye-catching red X.
If the file is waiting to be synced, or is currently syncing, the overlay
If the file is waiting to be synced, or is currently syncing, the overlay
icon displays a blue cycling icon.
When the client is offline, no icons are shown to reflect that the
folder is currently out of sync and no changes are synced to the server.
When the client is offline, no icons are shown to reflect that the
folder is currently out of sync and no changes are synced to the server.
The overlay icon of a synced directory indicates the status of the files in the
directory. If there are any sync errors, the directory is marked with a warning
The overlay icon of a synced directory indicates the status of the files in the
directory. If there are any sync errors, the directory is marked with a warning
icon.
If a directory includes ignored files that are marked with warning icons
If a directory includes ignored files that are marked with warning icons
that does not change the status of the parent directories.
Sharing From Your Desktop
-------------------------
The Nextcloud desktop sync client integrates with your file manager: Finder on
Mac OS X, Explorer on Windows, and Nautilus on Linux. (Linux users must install
the ``Nextcloud-client-nautilus`` plugin.) You can create share links, and share
The Nextcloud desktop sync client integrates with your file manager: Finder on
macOS, Explorer on Windows, and Nautilus on Linux. (Linux users must install
the ``Nextcloud-client-nautilus`` plugin.) You can create share links, and share
with internal Nextcloud users the same way as in your Nextcloud Web interface.
.. figure:: images/mac-share.png
:alt: Sync client integration in Windows Explorer.
Right-click your systray icon, hover over the account you want to use, and
left-click "Open folder [folder name] to quickly enter your local Nextcloud
folder. Right-click the file or folder you want to share to expose the share
Right-click your systray icon, hover over the account you want to use, and
left-click "Open folder [folder name] to quickly enter your local Nextcloud
folder. Right-click the file or folder you want to share to expose the share
dialog, and click **Share with Nextcloud**.
.. figure:: images/share-1.png
:alt: Sharing from Windows Explorer.
The share dialog has all the same options as your Nextcloud Web interface.
.. figure:: images/share-2.png
:alt: Share dialog in Windows Explorer.
Use **Share with Nextcloud** to see who you have shared with, and to modify
their permissions, or to delete the share.
Use **Share with Nextcloud** to see who you have shared with, and to modify
their permissions, or to delete the share.
Activity Window
---------------
The Activity window contains the log of your recent activities, organized over
three tabs: **Server Activities**, which includes new shares and files
downloaded and deleted, **Sync Protocol**, which displays local activities such
as which local folders your files went into, and **Not Synced** shows errors
The Activity window contains the log of your recent activities, organized over
three tabs: **Server Activities**, which includes new shares and files
downloaded and deleted, **Sync Protocol**, which displays local activities such
as which local folders your files went into, and **Not Synced** shows errors
such as files not synced. Double clicking an entry pointing to an existing
file in **Server Activities** or **Sync Protocol** will open the folder containing
the file and highlight it.
.. figure:: images/client-8.png
:alt: Activity windows logs all server and client activities.
Server Notifications
--------------------
Starting with version 2.2.0, the client will display notifications from your
Nextcloud server that require manual interaction by you. For example, when a
user on a remote Nextcloud creates a new Federated share for you, you can accept
Starting with version 2.2.0, the client will display notifications from your
Nextcloud server that require manual interaction by you. For example, when a
user on a remote Nextcloud creates a new Federated share for you, you can accept
it from your desktop client.
The desktop client automatically checks for available notifications
automatically on a regular basis. Notifications are displayed in the Server
Activity tab, and if you have **Show Desktop Notifications** enabled (General
The desktop client automatically checks for available notifications
automatically on a regular basis. Notifications are displayed in the Server
Activity tab, and if you have **Show Desktop Notifications** enabled (General
tab) you'll also see a systray notification.
.. figure:: images/client-12.png
:alt: Activity window with notification.
This also displays notifications sent to users by the Nextcloud admin via the
This also displays notifications sent to users by the Nextcloud admin via the
Announcements app.
General Window
--------------
The General window has configuration options such as **Launch on System
Startup**, **Use Monochrome Icons**, and **Show Desktop Notifications**. This
is where you will find the **Edit Ignored Files** button, to launch the ignored
files editor, and **Ask confirmation before downloading
The General window has configuration options such as **Launch on System
Startup**, **Use Monochrome Icons**, and **Show Desktop Notifications**. This
is where you will find the **Edit Ignored Files** button, to launch the ignored
files editor, and **Ask confirmation before downloading
folders larger than [folder size]**.
.. figure:: images/client-9.png
@ -232,7 +232,7 @@ Using the Network Window
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
The Network settings window enables you to define network proxy settings, and
The Network settings window enables you to define network proxy settings, and
also to limit download and upload bandwidth.
.. figure:: images/settings_network.png
@ -244,20 +244,20 @@ Using the Ignored Files Editor
.. index:: ignored files, exclude files, pattern
You might have some local files or directories that you do not want to backup
You might have some local files or directories that you do not want to backup
and store on the server. To identify and exclude these files or directories, you
can use the *Ignored Files Editor* (General tab.)
.. figure:: images/ignored_files_editor.png
For your convenience, the editor is pre-populated with a default list of
typical
ignore patterns. These patterns are contained in a system file (typically
``sync-exclude.lst``) located in the Nextcloud Client application directory. You
cannot modify these pre-populated patterns directly from the editor. However,
if
necessary, you can hover over any pattern in the list to show the path and
filename associated with that pattern, locate the file, and edit the
For your convenience, the editor is pre-populated with a default list of
typical
ignore patterns. These patterns are contained in a system file (typically
``sync-exclude.lst``) located in the Nextcloud Client application directory. You
cannot modify these pre-populated patterns directly from the editor. However,
if
necessary, you can hover over any pattern in the list to show the path and
filename associated with that pattern, locate the file, and edit the
``sync-exclude.lst`` file.
.. note:: Modifying the global exclude definition file might render the client
@ -267,14 +267,14 @@ Each line in the editor contains an ignore pattern string. When creating custom
patterns, in addition to being able to use normal characters to define an
ignore pattern, you can use wildcards characters for matching values. As an
example, you can use an asterisk (``*``) to identify an arbitrary number of
characters or a question mark (``?``) to identify a single character.
characters or a question mark (``?``) to identify a single character.
Patterns that end with a slash character (``/``) are applied to only directory
components of the path being checked.
.. note:: Custom entries are currently not validated for syntactical
correctness by the editor, so you will not see any warnings for bad
syntax. If your synchronization does not work as you expected, check your
syntax. If your synchronization does not work as you expected, check your
syntax.
Each pattern string in the list is preceded by a checkbox. When the check box
@ -288,8 +288,8 @@ this list:
- The Nextcloud Client always excludes files containing characters that cannot
be synchronized to other file systems.
- Files are removed that cause individual errors three times during a
synchronization. However, the client provides the option of retrying a
- Files are removed that cause individual errors three times during a
synchronization. However, the client provides the option of retrying a
synchronization three additional times on files that produce errors.
For more detailed information see :ref:`ignored-files-label`.

View File

@ -4,7 +4,7 @@ Appendix C: Troubleshooting
The following two general issues can result in failed synchronization:
- The server setup is incorrect.
- The client contains a bug.
- The client contains a bug.
When reporting bugs, it is helpful if you first determine what part of the
system is causing the issue.
@ -16,7 +16,7 @@ Identifying Basic Functionality Problems
The first step in troubleshooting synchronization issues is to verify that
you can log on to the Nextcloud web application. To verify connectivity to the
Nextcloud server try logging in via your Web browser.
If you are not prompted for your username and password, or if a red warning
box appears on the page, your server setup requires modification. Please verify
that your server installation is working correctly.
@ -30,7 +30,7 @@ Identifying Basic Functionality Problems
Verify that you can log on to Nextcloud's WebDAV server. To verify connectivity
with the Nextcloud WebDAV server:
- Open a browser window and enter the address to the Nextcloud WebDAV server.
- Open a browser window and enter the address to the Nextcloud WebDAV server.
For example, if your Nextcloud instance is installed at
``http://yourserver.com/nextcloud``, your WebDAV server address is
@ -40,29 +40,29 @@ Identifying Basic Functionality Problems
correct credentials, authentication fails, please ensure that your
authentication backend is configured properly.
:Use a WebDAV command line tool to test:
:Use a WebDAV command line tool to test:
A more sophisticated test method for troubleshooting synchronization issues
is to use a WebDAV command line client and log into the Nextcloud WebDAV server.
One such command line client -- called ``cadaver`` -- is available for Linux
distributions. You can use this application to further verify that the WebDAV
server is running properly using PROPFIND calls.
server is running properly using PROPFIND calls.
As an example, after installing the ``cadaver`` app, you can issue the
``propget`` command to obtain various properties pertaining to the current
directory and also verify WebDAV server connection.
"CSync unknown error"
---------------------
If you see this error message stop your client, delete the
``._sync_xxxxxxx.db`` file, and then restart your client.
There is a hidden ``._sync_xxxxxxx.db`` file inside the folder of every account
configured on your client.
configured on your client.
.. NOTE::
Please note that this will also erase some of your settings about which
files to download.
See https://github.com/owncloud/client/issues/5226 for more discussion of this
issue.
@ -145,7 +145,7 @@ mentioned above to save the log to a file.
restarting the client using the following command:
* Windows: ``C:\Program Files (x86)\Nextcloud\nextcloud.exe --logwindow``
* Mac OS X: ``/Applications/nextcloud.app/Contents/MacOS/nextcloud --logwindow``
* macOS: ``/Applications/nextcloud.app/Contents/MacOS/nextcloud --logwindow``
* Linux: ``nextcloud --logwindow``
Saving Files Directly
@ -184,7 +184,7 @@ The Nextcloud server also maintains an Nextcloud specific log file. This log fil
must be enabled through the Nextcloud Administration page. On that page, you can
adjust the log level. We recommend that when setting the log file level that
you set it to a verbose level like ``Debug`` or ``Info``.
You can view the server log file using the web interface or you can open it
directly from the file system in the Nextcloud server data directory.
@ -202,21 +202,21 @@ Nextcloud-related problems. For Apache on Linux, the error logs are typically
located in the ``/var/log/apache2`` directory. Some helpful files include the
following:
- ``error_log`` -- Maintains errors associated with PHP code.
- ``error_log`` -- Maintains errors associated with PHP code.
- ``access_log`` -- Typically records all requests handled by the server; very
useful as a debugging tool because the log line contains information specific
to each request and its result.
You can find more information about Apache logging at
``http://httpd.apache.org/docs/current/logs.html``.
Core Dumps
----------
On Mac OS X and Linux systems, and in the unlikely event the client software
On macOS and Linux systems, and in the unlikely event the client software
crashes, the client is able to write a core dump file. Obtaining a core dump
file can assist Nextcloud Customer Support tremendously in the debugging
process.
process.
To enable the writing of core dump files, you must define the
``OWNCLOUD_CORE_DUMP`` environment variable on the system.
@ -228,7 +228,7 @@ OWNCLOUD_CORE_DUMP=1 nextcloud
```
This command starts the client with core dumping enabled and saves the files in
the current working directory.
the current working directory.
.. note:: Core dump files can be fairly large. Before enabling core dumps on
your system, ensure that you have enough disk space to accommodate these files.

View File

@ -8,7 +8,7 @@ Icon
The Nextcloud Client remains in the background and is visible
as an icon in the system tray (Windows, KDE), status bar
(MAC OS X), or notification area (Ubuntu).
(macOS), or notification area (Ubuntu).
.. image:: images/icon.png
@ -17,7 +17,7 @@ Menu
.. image:: images/menu.png
A right click on the icon (left click on Ubuntu and Mac OS X)
A right click on the icon (left click on Ubuntu and macOS)
provides the following menu:
* ``Open Nextcloud in browser``: Opens the Nextcloud web interface
@ -124,7 +124,7 @@ The tab provides several useful options:
* ``Show Desktop Nofications``: When checked, bubble notifications when
a set of sync operations has been performed are provided.
* ``Use Monochrome Icons``: Use less obtrusive icons. Especially useful
on Mac OS X.
on macOS.
* ``About``: provides information about authors as well as build conditions.
This information is valuable when submitting a support request.
@ -179,11 +179,11 @@ The Ignored Files Editor
.. index:: ignored files, exclude files, pattern
Nextcloud Client has the ability to exclude files from the sync process.
The ignored files editor allows editing of custom patterns for files or
directories that should be excluded from the sync process.
The ignored files editor allows editing of custom patterns for files or
directories that should be excluded from the sync process.
There is a system wide list of default ignore patterns. These global defaults
cannot be directly modified within the editor. Hovering with the mouse will
There is a system wide list of default ignore patterns. These global defaults
cannot be directly modified within the editor. Hovering with the mouse will
reveal the location of the global exclude definition file.
.. image:: images/ignored_files_editor.png
@ -206,9 +206,9 @@ which are matched by this pattern are fleeting metadata which the client will
correctness by the editor, but might fail to load correctly.
In addition to this list, Nextcloud Client always excludes files with
characters that cannot be synced to other file systems.
characters that cannot be synced to other file systems.
With version 1.5.0 it also ignores files that caused individual errors
With version 1.5.0 it also ignores files that caused individual errors
while syncing for a three times. These are listed in the activity view.
There also is a button to retry the sync for another three times.

View File

@ -19,6 +19,7 @@
#include <QtNetwork/QLocalSocket>
#include <qcoreevent.h>
#include <QStandardPaths>
#include <QFile>
#include "ownclouddolphinpluginhelper.h"
#include "config.h"
@ -68,12 +69,14 @@ void OwncloudDolphinPluginHelper::tryConnect()
if (_socket.state() != QLocalSocket::UnconnectedState) {
return;
}
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
runtimeDir.append( QChar('/'));
runtimeDir.append( QLatin1String(APPLICATION_SHORTNAME) );
QString socketPath = QStandardPaths::locate(QStandardPaths::RuntimeLocation,
APPLICATION_SHORTNAME,
QStandardPaths::LocateDirectory);
if(socketPath.isEmpty())
return;
const QString socketPath = runtimeDir + QLatin1String("/socket");
_socket.connectToServer(socketPath);
_socket.connectToServer(socketPath + QLatin1String("/socket"));
}
void OwncloudDolphinPluginHelper::slotReadyRead()

View File

@ -35,6 +35,7 @@ from gi.repository import GObject, Nautilus
appname = 'ownCloud'
print("Initializing "+appname+"-client-nautilus extension")
print("Using python version {}".format(sys.version_info))
def get_local_path(url):
if url[0:7] == 'file://':
@ -64,7 +65,7 @@ class SocketConnect(GObject.GObject):
self._listeners = [self._update_registered_paths, self._get_version]
self._remainder = ''.encode()
self.protocolVersion = '1.0'
self.nautilusVFSFile_table = {} # not needed in this object actually but shared
self.nautilusVFSFile_table = {} # not needed in this object actually but shared
# all over the other objects.
# returns true when one should try again!
@ -96,19 +97,16 @@ class SocketConnect(GObject.GObject):
self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock_file = os.path.join(get_runtime_dir(), appname, "socket")
try:
print("Socket File: " + sock_file)
self._sock.connect(sock_file) # fails if sock_file doesn't exist
self.connected = True
print("Setting connected to %r." % self.connected )
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
print("Socket watch id: " + str(self._watch_id))
self.sendCommand('VERSION:\n')
self.sendCommand('GET_STRINGS:\n')
return False # Don't run again
except Exception as e:
print("Could not connect to unix socket. " + str(e))
print("Could not connect to unix socket " + sock_file + ". " + str(e))
except Exception as e: # Bad habbit
print("Connect could not be established, try again later.")
self._sock.close()
@ -131,7 +129,7 @@ class SocketConnect(GObject.GObject):
# Parses response lines out of collected data, returns list of strings
def get_available_responses(self):
end = self._remainder.rfind('\n'.encode())
end = self._remainder.rfind(b'\n')
if end == -1:
return []
data = self._remainder[:end]
@ -152,7 +150,7 @@ class SocketConnect(GObject.GObject):
return True # Run again
def handle_server_response(self, line):
print("Server response: " + line)
# print("Server response: " + line)
parts = line.split(':')
action = parts[0]
args = parts[1:]
@ -342,7 +340,7 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
def context_menu_action(self, menu, action, filename):
print("Context menu: " + action + ' ' + filename)
# print("Context menu: " + action + ' ' + filename)
socketConnect.sendCommand(action + ":" + filename + "\n")

View File

@ -23,17 +23,16 @@
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkProxy>
#include <qdebug.h>
#include "account.h"
#include "clientproxy.h"
#include "configfile.h" // ONLY ACCESS THE STATIC FUNCTIONS!
#include "creds/httpcredentials.h"
#include "simplesslerrorhandler.h"
#include "syncengine.h"
#include "common/syncjournaldb.h"
#include "config.h"
#include "connectionvalidator.h"
#include "cmd.h"
@ -83,8 +82,6 @@ struct CmdOptions
// So we have to use a global variable
CmdOptions *opts = 0;
const qint64 timeoutToUseMsec = qMax(1000, ConnectionValidator::DefaultCallingIntervalMsec - 5 * 1000);
class EchoDisabler
{
public:
@ -327,7 +324,6 @@ int main(int argc, char **argv)
options.restartTimes = 3;
options.uplimit = 0;
options.downlimit = 0;
ClientProxy clientProxy;
parseOptions(app.arguments(), &options);
@ -439,8 +435,6 @@ int main(int argc, char **argv)
} else {
qFatal("Could not read httpproxy. The proxy should have the format \"http://hostname:port\".");
}
} else {
clientProxy.setupQtProxyFromConfig();
}
SimpleSslErrorHandler *sslErrorHandler = new SimpleSslErrorHandler;
@ -454,24 +448,29 @@ int main(int argc, char **argv)
account->setCredentials(cred);
account->setSslErrorHandler(sslErrorHandler);
//obtain capabilities using event loop
QEventLoop loop;
// Perform a call to get the capabilities.
if (!options.nonShib) {
// Do not do it if '--nonshib' was passed. This mean we should only connect to the 'nonshib'
// dav endpoint. Since we do not get the capabilities, in that case, this has the additional
// side effect that chunking-ng will be disabled. (because otherwise it would use the new
// 'dav' endpoint instead of the nonshib one (which still use the old chunking)
JsonApiJob *job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/capabilities"));
job->setTimeout(timeoutToUseMsec);
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) {
auto caps = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
qDebug() << "Server capabilities" << caps;
account->setCapabilities(caps.toVariantMap());
loop.quit();
});
job->start();
QEventLoop loop;
JsonApiJob *job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/capabilities"));
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) {
auto caps = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
qDebug() << "Server capabilities" << caps;
account->setCapabilities(caps.toVariantMap());
loop.quit();
});
job->start();
loop.exec();
loop.exec();
if (job->reply()->error() != QNetworkReply::NoError){
std::cout<<"Error connecting to server\n";
return EXIT_FAILURE;
if (job->reply()->error() != QNetworkReply::NoError){
std::cout<<"Error connecting to server\n";
return EXIT_FAILURE;
}
}
// much lower age than the default since this utility is usually made to be run right after a change in the tests

View File

@ -537,4 +537,22 @@ bool FileSystem::isLnkFile(const QString &filename)
return filename.endsWith(".lnk");
}
bool FileSystem::isJunction(const QString &filename)
{
#ifdef Q_OS_WIN
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFileEx((const wchar_t *)filename.utf16(), FindExInfoBasic, &findData, FindExSearchNameMatch, NULL, 0);
if (hFind != INVALID_HANDLE_VALUE) {
FindClose(hFind);
return false;
}
return findData.dwFileAttributes != INVALID_FILE_ATTRIBUTES
&& findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT
&& findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT;
#else
Q_UNUSED(filename);
return false;
#endif
}
} // namespace OCC

View File

@ -141,8 +141,16 @@ namespace FileSystem {
*/
bool OCSYNC_EXPORT isFileLocked(const QString &fileName);
/**
* Returns whether the file is a shortcut file (ends with .lnk)
*/
bool OCSYNC_EXPORT isLnkFile(const QString &filename);
/**
* Returns whether the file is a junction (windows only)
*/
bool OCSYNC_EXPORT isJunction(const QString &filename);
/*
* This function takes a path and converts it to a UNC representation of the
* string. That means that it prepends a \\?\ (unless already UNC) and converts

View File

@ -254,15 +254,17 @@ void Utility::usleep(int usec)
QThread::usleep(usec);
}
bool Utility::fsCasePreserving()
{
#ifdef WITH_TESTING
// This can be overriden from the tests
OCSYNC_EXPORT bool fsCasePreserving_override = []()-> bool {
QByteArray env = qgetenv("OWNCLOUD_TEST_CASE_PRESERVING");
if (!env.isEmpty())
return env.toInt();
#endif
return Utility::isWindows() || Utility::isMac();
}();
return isWindows() || isMac();
bool Utility::fsCasePreserving()
{
return fsCasePreserving_override;
}
bool Utility::fileNamesEqual(const QString &fn1, const QString &fn2)

View File

@ -17,4 +17,3 @@
#cmakedefine HAVE___MINGW_ASPRINTF 1
#cmakedefine HAVE_ASPRINTF 1
#cmakedefine WITH_TESTING 1

View File

@ -126,12 +126,7 @@ int csync_update(CSYNC *ctx) {
}
int csync_reconcile(CSYNC *ctx) {
int rc = -1;
if (ctx == NULL) {
errno = EBADF;
return -1;
}
Q_ASSERT(ctx);
ctx->status_code = CSYNC_STATUS_OK;
/* Reconciliation for local replica */
@ -140,54 +135,31 @@ int csync_reconcile(CSYNC *ctx) {
ctx->current = LOCAL_REPLICA;
rc = csync_reconcile_updates(ctx);
csync_reconcile_updates(ctx);
qCInfo(lcCSync) << "Reconciliation for local replica took " << timer.elapsed() / 1000.
<< "seconds visiting " << ctx->local.files.size() << " files.";
if (rc < 0) {
if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR );
}
return rc;
}
/* Reconciliation for remote replica */
timer.restart();
ctx->current = REMOTE_REPLICA;
rc = csync_reconcile_updates(ctx);
csync_reconcile_updates(ctx);
qCInfo(lcCSync) << "Reconciliation for remote replica took " << timer.elapsed() / 1000.
<< "seconds visiting " << ctx->remote.files.size() << " files.";
if (rc < 0) {
if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR );
}
return rc;
}
ctx->status |= CSYNC_STATUS_RECONCILE;
rc = 0;
return rc;
return 0;
}
/*
* local visitor which calls the user visitor with repacked stat info.
*/
static int _csync_treewalk_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
int rc = 0;
csync_treewalk_visit_func *visitor = NULL;
_csync_treewalk_context *twctx = NULL;
static int _csync_treewalk_visitor(csync_file_stat_t *cur, CSYNC * ctx, const csync_treewalk_visit_func &visitor) {
csync_s::FileMap *other_tree = nullptr;
if (ctx == NULL) {
return -1;
}
/* we need the opposite tree! */
switch (ctx->current) {
case LOCAL_REPLICA:
@ -220,80 +192,41 @@ static int _csync_treewalk_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
ctx->status_code = CSYNC_STATUS_OK;
twctx = (_csync_treewalk_context*) ctx->callbacks.userdata;
if (twctx == NULL) {
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
return -1;
}
if (twctx->instruction_filter > 0 &&
!(twctx->instruction_filter & cur->instruction) ) {
return 0;
}
visitor = (csync_treewalk_visit_func*)(twctx->user_visitor);
if (visitor != NULL) {
rc = (*visitor)(cur, other, twctx->userdata);
return rc;
}
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
return -1;
Q_ASSERT(visitor);
return visitor(cur, other);
}
/*
* treewalk function, called from its wrappers below.
*
* it encapsulates the user visitor function, the filter and the userdata
* into a treewalk_context structure and calls the rb treewalk function,
* which calls the local _csync_treewalk_visitor in this module.
* The user visitor is called from there.
*/
static int _csync_walk_tree(CSYNC *ctx, csync_s::FileMap *tree, csync_treewalk_visit_func *visitor, int filter)
static int _csync_walk_tree(CSYNC *ctx, csync_s::FileMap &tree, const csync_treewalk_visit_func &visitor)
{
_csync_treewalk_context tw_ctx;
int rc = 0;
tw_ctx.userdata = ctx->callbacks.userdata;
tw_ctx.user_visitor = visitor;
tw_ctx.instruction_filter = filter;
ctx->callbacks.userdata = &tw_ctx;
for (auto &pair : *tree) {
if (_csync_treewalk_visitor(pair.second.get(), ctx) < 0) {
rc = -1;
break;
for (auto &pair : tree) {
if (_csync_treewalk_visitor(pair.second.get(), ctx, visitor) < 0) {
return -1;
}
}
if( rc < 0 ) {
if( ctx->status_code == CSYNC_STATUS_OK )
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR);
}
ctx->callbacks.userdata = tw_ctx.userdata;
return rc;
return 0;
}
/*
* wrapper function for treewalk on the remote tree
*/
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter)
int csync_walk_remote_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor)
{
ctx->status_code = CSYNC_STATUS_OK;
ctx->current = REMOTE_REPLICA;
return _csync_walk_tree(ctx, &ctx->remote.files, visitor, filter);
return _csync_walk_tree(ctx, ctx->remote.files, visitor);
}
/*
* wrapper function for treewalk on the local tree
*/
int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter)
int csync_walk_local_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor)
{
ctx->status_code = CSYNC_STATUS_OK;
ctx->current = LOCAL_REPLICA;
return _csync_walk_tree(ctx, &ctx->local.files, visitor, filter);
return _csync_walk_tree(ctx, ctx->local.files, visitor);
}
int csync_s::reinitialize() {
@ -310,9 +243,6 @@ int csync_s::reinitialize() {
renames.folder_renamed_from.clear();
renames.folder_renamed_to.clear();
local_discovery_style = LocalDiscoveryStyle::FilesystemOnly;
locally_touched_dirs.clear();
status = CSYNC_STATUS_INIT;
SAFE_FREE(error_string);

View File

@ -40,6 +40,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <config_csync.h>
#include <functional>
#include <memory>
#include <QByteArray>
#include "common/remotepermissions.h"
@ -64,40 +65,17 @@ enum csync_status_codes_e {
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
*/
CSYNC_STATUS_UNSUCCESSFUL, /* Unspecific problem happend */
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
CSYNC_STATUS_STATEDB_LOAD_ERROR, /* Statedb can not be loaded. */
CSYNC_STATUS_STATEDB_CORRUPTED, /* Statedb is corrupted */
CSYNC_STATUS_NO_MODULE, /* URL passed to csync does not start with owncloud:// or ownclouds:// */
CSYNC_STATUS_TIMESKEW, /* OBSOLETE */
CSYNC_STATUS_FILESYSTEM_UNKNOWN, /* UNUSED */
CSYNC_STATUS_TREE_ERROR, /* csync trees could not be created */
CSYNC_STATUS_PARAM_ERROR, /* parameter is zero where not expected */
CSYNC_STATUS_UPDATE_ERROR, /* general update or discovery error */
CSYNC_STATUS_RECONCILE_ERROR, /* general reconcile error */
CSYNC_STATUS_PROPAGATE_ERROR, /* OBSOLETE */
CSYNC_STATUS_REMOTE_ACCESS_ERROR, /* UNUSED */
CSYNC_STATUS_REMOTE_CREATE_ERROR, /* UNUSED */
CSYNC_STATUS_REMOTE_STAT_ERROR, /* UNUSED */
CSYNC_STATUS_LOCAL_CREATE_ERROR, /* UNUSED */
CSYNC_STATUS_LOCAL_STAT_ERROR, /* UNUSED */
CSYNC_STATUS_PROXY_ERROR, /* UNUSED */
CSYNC_STATUS_LOOKUP_ERROR, /* Neon fails to find proxy. Almost OBSOLETE */
CSYNC_STATUS_SERVER_AUTH_ERROR, /* UNUSED */
CSYNC_STATUS_PROXY_AUTH_ERROR, /* UNUSED */
CSYNC_STATUS_CONNECT_ERROR, /* neon driven connection failed */
CSYNC_STATUS_TIMEOUT, /* UNUSED */
CSYNC_STATUS_HTTP_ERROR, /* UNUSED */
CSYNC_STATUS_PERMISSION_DENIED, /* */
CSYNC_STATUS_NOT_FOUND,
CSYNC_STATUS_FILE_EXISTS,
CSYNC_STATUS_OUT_OF_SPACE,
CSYNC_STATUS_QUOTA_EXCEEDED, /* UNUSED */
CSYNC_STATUS_SERVICE_UNAVAILABLE,
CSYNC_STATUS_STORAGE_UNAVAILABLE,
CSYNC_STATUS_FILE_SIZE_ERROR,
CSYNC_STATUS_CONTEXT_LOST,
CSYNC_STATUS_MERGE_FILETREE_ERROR,
CSYNC_STATUS_CSYNC_STATUS_ERROR,
CSYNC_STATUS_OPENDIR_ERROR,
CSYNC_STATUS_READDIR_ERROR,
CSYNC_STATUS_OPEN_ERROR,
@ -306,29 +284,27 @@ CSYNC_STATUS OCSYNC_EXPORT csync_get_status(CSYNC *ctx);
/* Used for special modes or debugging */
int OCSYNC_EXPORT csync_set_status(CSYNC *ctx, int status);
typedef int csync_treewalk_visit_func(csync_file_stat_t *cur, csync_file_stat_t *other, void*);
using csync_treewalk_visit_func = std::function<int(csync_file_stat_t *cur, csync_file_stat_t *other)>;
/**
* @brief Walk the local file tree and call a visitor function for each file.
*
* @param ctx The csync context.
* @param visitor A callback function to handle the file info.
* @param filter A filter, built from or'ed csync_instructions_e
*
* @return 0 on success, less than 0 if an error occurred.
*/
int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor);
/**
* @brief Walk the remote file tree and call a visitor function for each file.
*
* @param ctx The csync context.
* @param visitor A callback function to handle the file info.
* @param filter A filter, built from and'ed csync_instructions_e
*
* @return 0 on success, less than 0 if an error occurred.
*/
int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor);
/**
* @brief Get the csync status string.

View File

@ -217,8 +217,8 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeC
}
#endif
/* We create a desktop.ini on Windows for the sidebar icon, make sure we don't sync them. */
if (blen == 11) {
/* We create a Desktop.ini on Windows for the sidebar icon, make sure we don't sync it. */
if (blen == 11 && path == bname) {
rc = csync_fnmatch("Desktop.ini", bname, 0);
if (rc == 0) {
match = CSYNC_FILE_SILENTLY_EXCLUDED;

View File

@ -32,19 +32,8 @@
* should always be larger than the highest system errno. */
#define CSYNC_CUSTOM_ERRNO_BASE 10000
#define ERRNO_GENERAL_ERROR CSYNC_CUSTOM_ERRNO_BASE+2
#define ERRNO_LOOKUP_ERROR CSYNC_CUSTOM_ERRNO_BASE+3
#define ERRNO_USER_UNKNOWN_ON_SERVER CSYNC_CUSTOM_ERRNO_BASE+4
#define ERRNO_PROXY_AUTH CSYNC_CUSTOM_ERRNO_BASE+5
#define ERRNO_CONNECT CSYNC_CUSTOM_ERRNO_BASE+6
#define ERRNO_TIMEOUT CSYNC_CUSTOM_ERRNO_BASE+7
#define ERRNO_PRECONDITION CSYNC_CUSTOM_ERRNO_BASE+8
#define ERRNO_RETRY CSYNC_CUSTOM_ERRNO_BASE+9
#define ERRNO_REDIRECT CSYNC_CUSTOM_ERRNO_BASE+10
#define ERRNO_WRONG_CONTENT CSYNC_CUSTOM_ERRNO_BASE+11
#define ERRNO_ERROR_STRING CSYNC_CUSTOM_ERRNO_BASE+13
#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14
#define ERRNO_USER_ABORT CSYNC_CUSTOM_ERRNO_BASE+16
#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17
#define ERRNO_FORBIDDEN CSYNC_CUSTOM_ERRNO_BASE+18

View File

@ -78,24 +78,6 @@ CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
status = CSYNC_STATUS_OK;
break;
/* The custom errnos first. */
case ERRNO_GENERAL_ERROR:
status = CSYNC_STATUS_UNSUCCESSFUL;
break;
case ERRNO_LOOKUP_ERROR: /* In Neon: Server or proxy hostname lookup failed */
status = CSYNC_STATUS_LOOKUP_ERROR;
break;
case ERRNO_USER_UNKNOWN_ON_SERVER: /* Neon: User authentication on server failed. */
status = CSYNC_STATUS_SERVER_AUTH_ERROR;
break;
case ERRNO_PROXY_AUTH:
status = CSYNC_STATUS_PROXY_AUTH_ERROR; /* Neon: User authentication on proxy failed */
break;
case ERRNO_CONNECT:
status = CSYNC_STATUS_CONNECT_ERROR; /* Network: Connection error */
break;
case ERRNO_TIMEOUT:
status = CSYNC_STATUS_TIMEOUT; /* Network: Timeout error */
break;
case ERRNO_SERVICE_UNAVAILABLE:
status = CSYNC_STATUS_SERVICE_UNAVAILABLE; /* Service temporarily down */
break;
@ -105,9 +87,6 @@ CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
case EFBIG:
status = CSYNC_STATUS_FILE_SIZE_ERROR; /* File larger than 2MB */
break;
case ERRNO_PRECONDITION:
case ERRNO_RETRY:
case ERRNO_REDIRECT:
case ERRNO_WRONG_CONTENT:
status = CSYNC_STATUS_HTTP_ERROR;
break;
@ -125,14 +104,12 @@ CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
case EEXIST: /* File exists */
status = CSYNC_STATUS_FILE_EXISTS;
break;
case EINVAL:
status = CSYNC_STATUS_PARAM_ERROR;
break;
case ENOSPC:
status = CSYNC_STATUS_OUT_OF_SPACE;
break;
/* All the remaining basic errnos: */
case EINVAL: /* Invalid argument */
case EIO: /* I/O error */
case ESRCH: /* No such process */
case EINTR: /* Interrupted system call */
@ -162,7 +139,6 @@ CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
case EMLINK: /* Too many links */
case EPIPE: /* Broken pipe */
case ERRNO_ERROR_STRING:
default:
status = default_status;
}

View File

@ -201,15 +201,7 @@ struct OCSYNC_EXPORT csync_s {
*/
bool read_remote_from_db = false;
LocalDiscoveryStyle local_discovery_style = LocalDiscoveryStyle::FilesystemOnly;
/**
* List of folder-relative directory paths that should be scanned on the
* filesystem if the local_discovery_style suggests it.
*
* Their parents will be scanned too. The paths don't start with a /.
*/
std::set<QByteArray> locally_touched_dirs;
std::function<bool(const QByteArray &)> should_discover_locally_fn;
bool ignore_hidden_files = true;
@ -227,17 +219,6 @@ struct OCSYNC_EXPORT csync_s {
csync_s &operator=(const csync_s &) = delete;
};
/*
* context for the treewalk function
*/
struct _csync_treewalk_context_s
{
csync_treewalk_visit_func *user_visitor;
int instruction_filter;
void *userdata;
};
typedef struct _csync_treewalk_context_s _csync_treewalk_context;
void set_errno_from_http_errcode( int err );
/**

View File

@ -92,7 +92,7 @@ static csync_file_stat_t *_csync_check_ignored(csync_s::FileMap *tree, const Byt
* (timestamp is newer), it is not overwritten. If both files, on the
* source and the destination, have been changed, the newer file wins.
*/
static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
static void _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
csync_s::FileMap *our_tree = nullptr;
csync_s::FileMap *other_tree = nullptr;
@ -442,11 +442,9 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
cur->path.constData());
}
}
return 0;
}
int csync_reconcile_updates(CSYNC *ctx) {
void csync_reconcile_updates(CSYNC *ctx) {
csync_s::FileMap *tree = nullptr;
switch (ctx->current) {
@ -461,12 +459,8 @@ int csync_reconcile_updates(CSYNC *ctx) {
}
for (auto &pair : *tree) {
if (_csync_merge_algorithm_visitor(pair.second.get(), ctx) < 0) {
ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
return -1;
}
_csync_merge_algorithm_visitor(pair.second.get(), ctx);
}
return 0;
}
/* vim: set ts=8 sw=2 et cindent: */

View File

@ -46,11 +46,9 @@
*
* @param ctx The csync context to use.
*
* @return 0 on success, < 0 on error.
*
* @todo Add an argument to set the algorithm to use.
*/
int OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx);
void OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx);
/**
* }@

View File

@ -108,15 +108,9 @@ static bool _csync_mtime_equal(time_t a, time_t b)
* See doc/dev/sync-algorithm.md for an overview.
*/
static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
Q_ASSERT(fs);
OCC::SyncJournalFileRecord base;
CSYNC_EXCLUDE_TYPE excluded = CSYNC_NOT_EXCLUDED;
if (fs == NULL) {
errno = EINVAL;
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
return -1;
}
if (fs->type == ItemTypeSkip) {
excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
} else {
@ -602,23 +596,12 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
const char *db_uri = uri;
if (ctx->current == LOCAL_REPLICA
&& ctx->local_discovery_style == LocalDiscoveryStyle::DatabaseAndFilesystem) {
if (ctx->current == LOCAL_REPLICA && ctx->should_discover_locally_fn) {
const char *local_uri = uri + strlen(ctx->local.uri);
if (*local_uri == '/')
++local_uri;
db_uri = local_uri;
do_read_from_db = true;
// Minor bug: local_uri doesn't have a trailing /. Example: Assume it's "d/foo"
// and we want to check whether we should read from the db. Assume "d/foo a" is
// in locally_touched_dirs. Then this check will say no, don't read from the db!
// (because "d/foo" < "d/foo a" < "d/foo/bar")
// C++14: Could skip the conversion to QByteArray here.
auto it = ctx->locally_touched_dirs.lower_bound(QByteArray(local_uri));
if (it != ctx->locally_touched_dirs.end() && it->startsWith(local_uri)) {
do_read_from_db = false;
}
do_read_from_db = !ctx->should_discover_locally_fn(QByteArray(local_uri));
}
if (!depth) {
@ -722,10 +705,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
// Now process to have a relative path to the sync root for the local replica, or to the data root on the remote.
dirent->path = fullpath;
if (ctx->current == LOCAL_REPLICA) {
if (dirent->path.size() <= (int)strlen(ctx->local.uri)) {
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
goto error;
}
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
// "len + 1" to include the slash in-between.
dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
}

View File

@ -40,7 +40,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
break;
case LOCAL_REPLICA:
if( ctx->callbacks.update_callback ) {
ctx->callbacks.update_callback(ctx->current, name, ctx->callbacks.update_callback_userdata);
ctx->callbacks.update_callback(/*local=*/true, name, ctx->callbacks.update_callback_userdata);
}
return csync_vio_local_opendir(name);
break;

View File

@ -48,6 +48,8 @@ set(client_SRCS
accountmanager.cpp
accountsettings.cpp
application.cpp
clientproxy.cpp
connectionvalidator.cpp
folder.cpp
folderman.cpp
folderstatusmodel.cpp

View File

@ -34,6 +34,7 @@
#include "tooltipupdater.h"
#include "filesystem.h"
#include "clientsideencryptionjobs.h"
#include "syncresult.h"
#include <math.h>
@ -335,9 +336,36 @@ void AccountSettings::slotUnlockFolderSuccess(const QByteArray& fileId)
{
qCInfo(lcAccountSettings()) << "Unlocking success!";
}
void AccountSettings::slotMarkSubfolderEncrpted(const QByteArray& fileId)
bool AccountSettings::canEncryptOrDecrypt (const FolderStatusModel::SubFolderInfo* info) {
if (info->_folder->syncResult().status() != SyncResult::Status::Success) {
QMessageBox msgBox;
msgBox.setText("Please wait for the folder to sync before trying to encrypt it.");
msgBox.exec();
return false;
}
// for some reason the actual folder in disk is info->_folder->path + info->_path.
QDir folderPath(info->_folder->path() + info->_path);
folderPath.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
if (folderPath.count() != 0) {
QMessageBox msgBox;
msgBox.setText("You cannot encyrpt a folder with contents, please remove the files \n"
"Wait for the new sync, then encrypt it.");
msgBox.exec();
return false;
}
return true;
}
void AccountSettings::slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo)
{
auto job = new OCC::SetEncryptionFlagApiJob(accountsState()->account(), fileId);
if (!canEncryptOrDecrypt(folderInfo)) {
return;
}
auto job = new OCC::SetEncryptionFlagApiJob(accountsState()->account(), folderInfo->_fileId);
connect(job, &OCC::SetEncryptionFlagApiJob::success, this, &AccountSettings::slotEncryptionFlagSuccess);
connect(job, &OCC::SetEncryptionFlagApiJob::error, this, &AccountSettings::slotEncryptionFlagError);
job->start();
@ -349,11 +377,17 @@ void AccountSettings::slotMarkSubfolderEncrpted(const QByteArray& fileId)
// 2 - Delete Metadata,
// 3 - Unlock Folder,
// 4 - Mark as Decrypted.
void AccountSettings::slotMarkSubfolderDecrypted(const QByteArray& fileId)
void AccountSettings::slotMarkSubfolderDecrypted(const FolderStatusModel::SubFolderInfo* folderInfo)
{
if (!canEncryptOrDecrypt(folderInfo)) {
return;
}
qDebug() << "Starting to mark as decrypted";
qDebug() << "Locking the folder";
auto lockJob = new LockEncryptFolderApiJob(accountsState()->account(), fileId);
auto lockJob = new LockEncryptFolderApiJob(accountsState()->account(), folderInfo->_fileId);
connect(lockJob, &LockEncryptFolderApiJob::success,
this, &AccountSettings::slotLockForDecryptionSuccess);
connect(lockJob, &LockEncryptFolderApiJob::error,
@ -444,13 +478,15 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
auto acc = _accountState->account();
if (acc->capabilities().clientSideEncryptionAvaliable()) {
// Verify if the folder is empty before attempting to encrypt.
bool isEncrypted = acc->e2e()->isFolderEncrypted(info->_path);
ac = menu.addAction( isEncrypted ? tr("Decrypt") : tr("Encrypt"));
if (not isEncrypted) {
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrpted(info->_fileId); });
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrpted(info); });
} else {
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info->_fileId); });
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); });
}
}
menu.exec(QCursor::pos());

View File

@ -25,6 +25,7 @@
#include "quotainfo.h"
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "folderstatusmodel.h"
class QModelIndex;
class QNetworkReply;
@ -55,7 +56,7 @@ public:
explicit AccountSettings(AccountState *accountState, QWidget *parent = 0);
~AccountSettings();
QSize sizeHint() const Q_DECL_OVERRIDE { return ownCloudGui::settingsDialogSize(); }
bool canEncryptOrDecrypt(const FolderStatusModel::SubFolderInfo* folderInfo);
signals:
void folderChanged();
@ -85,8 +86,8 @@ protected slots:
void slotOpenAccountWizard();
void slotAccountAdded(AccountState *);
void refreshSelectiveSyncStatus();
void slotMarkSubfolderEncrpted(const QByteArray& fileId);
void slotMarkSubfolderDecrypted(const QByteArray& fileId);
void slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo);
void slotMarkSubfolderDecrypted(const FolderStatusModel::SubFolderInfo* folderInfo);
void slotSubfolderContextMenuRequested(const QModelIndex& idx, const QPoint& point);
void slotCustomContextMenuRequested(const QPoint &);
void slotFolderListClicked(const QModelIndex &indx);

View File

@ -77,11 +77,6 @@ QStringList AccountState::connectionErrors() const
return _connectionErrors;
}
QString AccountState::connectionStatusString(ConnectionStatus status)
{
return ConnectionValidator::statusString(status);
}
AccountState::State AccountState::state() const
{
return _state;
@ -258,7 +253,7 @@ void AccountState::checkConnectivity()
void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors)
{
if (isSignedOut()) {
qCWarning(lcAccountState) << "Signed out, ignoring" << connectionStatusString(status) << _account->url().toString();
qCWarning(lcAccountState) << "Signed out, ignoring" << status << _account->url().toString();
return;
}
@ -281,8 +276,8 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
if (_connectionStatus != status) {
qCInfo(lcAccountState) << "AccountState connection status change: "
<< connectionStatusString(_connectionStatus) << "->"
<< connectionStatusString(status);
<< _connectionStatus << "->"
<< status;
_connectionStatus = status;
}
_connectionErrors = errors;

View File

@ -94,7 +94,6 @@ public:
ConnectionStatus connectionStatus() const;
QStringList connectionErrors() const;
static QString connectionStatusString(ConnectionStatus status);
State state() const;
static QString stateString(State state);

View File

@ -32,7 +32,7 @@ class ConfigFile;
* @brief The ClientProxy class
* @ingroup libsync
*/
class OWNCLOUDSYNC_EXPORT ClientProxy : public QObject
class ClientProxy : public QObject
{
Q_OBJECT
public:
@ -61,7 +61,7 @@ private:
QUrl _url;
};
OWNCLOUDSYNC_EXPORT QString printQNetworkProxy(const QNetworkProxy &proxy);
QString printQNetworkProxy(const QNetworkProxy &proxy);
}
#endif // CLIENTPROXY_H

View File

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

View File

@ -41,35 +41,6 @@ ConnectionValidator::ConnectionValidator(AccountPtr account, QObject *parent)
{
}
QString ConnectionValidator::statusString(Status stat)
{
switch (stat) {
case Undefined:
return QLatin1String("Undefined");
case Connected:
return QLatin1String("Connected");
case NotConfigured:
return QLatin1String("Not configured");
case ServerVersionMismatch:
return QLatin1String("Server Version Mismatch");
case CredentialsNotReady:
return QLatin1String("Credentials not ready");
case CredentialsWrong:
return QLatin1String("Credentials Wrong");
case SslError:
return QLatin1String("SSL Error");
case StatusNotFound:
return QLatin1String("Status not found");
case ServiceUnavailable:
return QLatin1String("Service unavailable");
case MaintenanceMode:
return QLatin1String("Maintenance mode");
case Timeout:
return QLatin1String("Timeout");
}
return QLatin1String("status undeclared.");
}
void ConnectionValidator::checkServerAndAuth()
{
if (!_account) {
@ -305,15 +276,15 @@ bool ConnectionValidator::setAndCheckServerVersion(const QString &version)
qCInfo(lcConnectionValidator) << _account->url() << "has server version" << version;
_account->setServerVersion(version);
// We cannot deal with servers < 5.0.0
// We cannot deal with servers < 7.0.0
if (_account->serverVersionInt()
&& _account->serverVersionInt() < Account::makeServerVersion(5, 0, 0)) {
&& _account->serverVersionInt() < Account::makeServerVersion(7, 0, 0)) {
_errors.append(tr("The configured server for this client is too old"));
_errors.append(tr("Please update to the latest server and restart the client."));
reportResult(ServerVersionMismatch);
return false;
}
// We attempt to work with servers >= 5.0.0 but warn users.
// We attempt to work with servers >= 7.0.0 but warn users.
// Check usages of Account::serverVersionUnsupported() for details.
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)

View File

@ -79,7 +79,7 @@ namespace OCC {
\endcode
*/
class OWNCLOUDSYNC_EXPORT ConnectionValidator : public QObject
class ConnectionValidator : public QObject
{
Q_OBJECT
public:
@ -98,8 +98,7 @@ public:
MaintenanceMode, // maintenance enabled in status.php
Timeout // actually also used for other errors on the authed request
};
static QString statusString(Status);
Q_ENUM(Status);
// How often should the Application ask this object to check for the connection?
enum { DefaultCallingIntervalMsec = 32 * 1000 };
@ -113,7 +112,7 @@ public slots:
void checkAuthentication();
signals:
void connectionResult(ConnectionValidator::Status status, QStringList errors);
void connectionResult(ConnectionValidator::Status status, const QStringList &errors);
protected slots:
void slotCheckServerAndAuth();

View File

@ -107,6 +107,9 @@ Folder::Folder(const FolderDefinition &definition,
_scheduleSelfTimer.setInterval(SyncEngine::minimumFileAgeForUpload);
connect(&_scheduleSelfTimer, &QTimer::timeout,
this, &Folder::slotScheduleThisFolder);
connect(ProgressDispatcher::instance(), &ProgressDispatcher::folderConflicts,
this, &Folder::slotFolderConflicts);
}
Folder::~Folder()
@ -119,6 +122,10 @@ void Folder::checkLocalPath()
{
const QFileInfo fi(_definition.localPath);
_canonicalLocalPath = fi.canonicalFilePath();
#ifdef Q_OS_MAC
// Workaround QTBUG-55896 (Should be fixed in Qt 5.8)
_canonicalLocalPath = _canonicalLocalPath.normalized(QString::NormalizationForm_C);
#endif
if (_canonicalLocalPath.isEmpty()) {
qCWarning(lcFolder) << "Broken symlink:" << _definition.localPath;
_canonicalLocalPath = _definition.localPath;
@ -964,6 +971,17 @@ void Folder::slotNextSyncFullLocalDiscovery()
_timeSinceLastFullLocalDiscovery.invalidate();
}
void Folder::slotFolderConflicts(const QString &folder, const QStringList &conflictPaths)
{
if (folder != _definition.alias)
return;
auto &r = _syncResult;
// If the number of conflicts is too low, adjust it upwards
if (conflictPaths.size() > r.numNewConflictItems() + r.numOldConflictItems())
r.setNumOldConflictItems(conflictPaths.size() - r.numNewConflictItems());
}
void Folder::scheduleThisFolderSoon()
{
if (!_scheduleSelfTimer.isActive()) {

View File

@ -20,7 +20,6 @@
#include "syncresult.h"
#include "progressdispatcher.h"
#include "common/syncjournaldb.h"
#include "clientproxy.h"
#include "networkjobs.h"
#include <csync.h>
@ -315,6 +314,13 @@ private slots:
/** Ensures that the next sync performs a full local discovery. */
void slotNextSyncFullLocalDiscovery();
/** Adjust sync result based on conflict data from IssuesWidget.
*
* This is pretty awkward, but IssuesWidget just keeps better track
* of conflicts across partial local discovery.
*/
void slotFolderConflicts(const QString &folder, const QStringList &conflictPaths);
private:
bool reloadExcludes();
@ -361,8 +367,6 @@ private:
SyncJournalDb _journal;
ClientProxy _clientProxy;
QScopedPointer<SyncRunFileLog> _fileLog;
QTimer _scheduleSelfTimer;

View File

@ -37,6 +37,7 @@
#include <QtCore>
#include <QMutableSetIterator>
#include <QSet>
#include <QNetworkProxy>
namespace OCC {

View File

@ -905,11 +905,16 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
<< FolderStatusDelegate::WarningCount
<< Qt::ToolTipRole;
if (progress.status() == ProgressInfo::Discovery
&& !progress._currentDiscoveredFolder.isEmpty()) {
pi->_overallSyncString = tr("Checking for changes in '%1'").arg(progress._currentDiscoveredFolder);
emit dataChanged(index(folderIndex), index(folderIndex), roles);
return;
if (progress.status() == ProgressInfo::Discovery) {
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
pi->_overallSyncString = tr("Checking for changes in remote '%1'").arg(progress._currentDiscoveredRemoteFolder);
emit dataChanged(index(folderIndex), index(folderIndex), roles);
return;
} else if (!progress._currentDiscoveredLocalFolder.isEmpty()) {
pi->_overallSyncString = tr("Checking for changes in local '%1'").arg(progress._currentDiscoveredLocalFolder);
emit dataChanged(index(folderIndex), index(folderIndex), roles);
return;
}
}
if (progress.status() == ProgressInfo::Reconcile) {

View File

@ -18,6 +18,7 @@
#include "issueswidget.h"
#include "configfile.h"
#include "syncresult.h"
#include "syncengine.h"
#include "logger.h"
#include "theme.h"
#include "folderman.h"
@ -45,6 +46,11 @@ namespace OCC {
*/
static const int maxIssueCount = 50000;
static QPair<QString, QString> pathsWithIssuesKey(const ProtocolItem::ExtraData &data)
{
return qMakePair(data.folderName, data.path);
}
IssuesWidget::IssuesWidget(QWidget *parent)
: QWidget(parent)
, _ui(new Ui::IssuesWidget)
@ -145,7 +151,14 @@ void IssuesWidget::hideEvent(QHideEvent *ev)
QWidget::hideEvent(ev);
}
void IssuesWidget::cleanItems(const QString &folder)
static bool persistsUntilLocalDiscovery(QTreeWidgetItem *item)
{
const auto data = ProtocolItem::extraData(item);
return data.status == SyncFileItem::Conflict
|| (data.status == SyncFileItem::FileIgnored && data.direction == SyncFileItem::Up);
}
void IssuesWidget::cleanItems(const std::function<bool(QTreeWidgetItem *)> &shouldDelete)
{
_ui->_treeWidget->setSortingEnabled(false);
@ -154,8 +167,8 @@ void IssuesWidget::cleanItems(const QString &folder)
int itemCnt = _ui->_treeWidget->topLevelItemCount();
for (int cnt = itemCnt - 1; cnt >= 0; cnt--) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
QString itemFolder = ProtocolItem::folderName(item);
if (itemFolder == folder) {
if (shouldDelete(item)) {
_pathsWithIssues.remove(pathsWithIssuesKey(ProtocolItem::extraData(item)));
delete item;
}
}
@ -190,7 +203,21 @@ void IssuesWidget::addItem(QTreeWidgetItem *item)
}
}
// Wipe any existing message for the same folder and path
auto newData = ProtocolItem::extraData(item);
if (_pathsWithIssues.contains(pathsWithIssuesKey(newData))) {
for (int i = 0; i < count; ++i) {
auto otherItem = _ui->_treeWidget->topLevelItem(i);
auto otherData = ProtocolItem::extraData(otherItem);
if (otherData.path == newData.path && otherData.folderName == newData.folderName) {
delete otherItem;
break;
}
}
}
_ui->_treeWidget->insertTopLevelItem(insertLoc, item);
_pathsWithIssues.insert(pathsWithIssuesKey(newData));
item->setHidden(!shouldBeVisible(item, currentAccountFilter(), currentFolderFilter()));
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
}
@ -209,9 +236,47 @@ void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
void IssuesWidget::slotProgressInfo(const QString &folder, const ProgressInfo &progress)
{
if (progress.status() == ProgressInfo::Starting) {
// The sync is restarting, clean the old items
cleanItems(folder);
if (progress.status() == ProgressInfo::Reconcile) {
// Wipe all non-persistent entries - as well as the persistent ones
// in cases where a local discovery was done.
auto f = FolderMan::instance()->folder(folder);
if (!f)
return;
const auto &engine = f->syncEngine();
const auto style = engine.lastLocalDiscoveryStyle();
cleanItems([&](QTreeWidgetItem *item) {
if (ProtocolItem::extraData(item).folderName != folder)
return false;
if (style == LocalDiscoveryStyle::FilesystemOnly)
return true;
if (!persistsUntilLocalDiscovery(item))
return true;
// Definitely wipe the entry if the file no longer exists
if (!QFileInfo(f->path() + ProtocolItem::extraData(item).path).exists())
return true;
auto path = QFileInfo(ProtocolItem::extraData(item).path).dir().path().toUtf8();
if (path == ".")
path.clear();
return engine.shouldDiscoverLocally(path);
});
}
if (progress.status() == ProgressInfo::Done) {
// We keep track very well of pending conflicts.
// Inform other components about them.
QStringList conflicts;
auto tree = _ui->_treeWidget;
for (int i = 0; i < tree->topLevelItemCount(); ++i) {
auto item = tree->topLevelItem(i);
auto data = ProtocolItem::extraData(item);
if (data.folderName == folder
&& data.status == SyncFileItem::Conflict) {
conflicts.append(data.path);
}
}
emit ProgressDispatcher::instance()->folderConflicts(folder, conflicts);
}
}
@ -285,13 +350,14 @@ bool IssuesWidget::shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAc
const QString &filterFolderAlias) const
{
bool visible = true;
auto status = ProtocolItem::status(item);
auto data = ProtocolItem::extraData(item);
auto status = data.status;
visible &= (_ui->showIgnores->isChecked() || status != SyncFileItem::FileIgnored);
visible &= (_ui->showWarnings->isChecked()
|| (status != SyncFileItem::SoftError
&& status != SyncFileItem::Restoration));
auto folderalias = ProtocolItem::folderName(item);
const auto &folderalias = data.folderName;
if (filterAccount) {
auto folder = FolderMan::instance()->folder(folderalias);
visible &= folder && folder->accountState() == filterAccount;
@ -415,12 +481,14 @@ void IssuesWidget::addError(const QString &folderAlias, const QString &message,
QTreeWidgetItem *twitem = new ProtocolItem(columns);
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setData(0, Qt::UserRole, timestamp);
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setData(2, Qt::UserRole, folderAlias);
twitem->setToolTip(3, message);
twitem->setData(3, Qt::UserRole, SyncFileItem::NormalError);
ProtocolItem::ExtraData data;
data.timestamp = timestamp;
data.folderName = folderAlias;
data.status = SyncFileItem::NormalError;
ProtocolItem::setExtraData(twitem, data);
addItem(twitem);
addErrorWidget(twitem, message, category);
@ -440,7 +508,7 @@ void IssuesWidget::addErrorWidget(QTreeWidgetItem *item, const QString &message,
auto button = new QPushButton("Retry all uploads", widget);
button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
auto folderAlias = ProtocolItem::folderName(item);
auto folderAlias = ProtocolItem::extraData(item).folderName;
connect(button, &QPushButton::clicked,
this, [this, folderAlias]() { retryInsufficentRemoteStorageErrors(folderAlias); });
layout->addWidget(button);

View File

@ -63,6 +63,7 @@ protected:
signals:
void copyToClipboard();
void issueCountUpdated(int);
void folderConflicts(QString folder, QStringList conflictPaths);
private slots:
void slotRefreshIssues();
@ -77,7 +78,7 @@ private:
QString currentFolderFilter() const;
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
const QString &filterFolderAlias) const;
void cleanItems(const QString &folder);
void cleanItems(const std::function<bool(QTreeWidgetItem *)> &shouldDelete);
void addItem(QTreeWidgetItem *item);
/// Add the special error widget for the category, if any
@ -89,6 +90,9 @@ private:
/// Each insert disables sorting, this timer reenables it
QTimer _reenableSorting;
/// Optimization: keep track of all folder/paths pairs that have an associated issue
QSet<QPair<QString, QString>> _pathsWithIssues;
Ui::IssuesWidget *_ui;
};
}

View File

@ -869,9 +869,12 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
Q_UNUSED(folder);
if (progress.status() == ProgressInfo::Discovery) {
if (!progress._currentDiscoveredFolder.isEmpty()) {
_actionStatus->setText(tr("Checking for changes in '%1'")
.arg(progress._currentDiscoveredFolder));
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
_actionStatus->setText(tr("Checking for changes in remote '%1'")
.arg(progress._currentDiscoveredRemoteFolder));
} else if (!progress._currentDiscoveredLocalFolder.isEmpty()) {
_actionStatus->setText(tr("Checking for changes in local '%1'")
.arg(progress._currentDiscoveredLocalFolder));
}
} else if (progress.status() == ProgressInfo::Done) {
QTimer::singleShot(2000, this, &ownCloudGui::slotComputeOverallSyncStatus);

View File

@ -32,6 +32,8 @@
#include <climits>
Q_DECLARE_METATYPE(OCC::ProtocolItem::ExtraData)
namespace OCC {
QString ProtocolItem::timeString(QDateTime dt, QLocale::FormatType format)
@ -43,54 +45,14 @@ QString ProtocolItem::timeString(QDateTime dt, QLocale::FormatType format)
return loc.toString(dt, dtFormat);
}
QString ProtocolItem::folderName(const QTreeWidgetItem *item)
ProtocolItem::ExtraData ProtocolItem::extraData(const QTreeWidgetItem *item)
{
return item->data(2, Qt::UserRole).toString();
return item->data(0, Qt::UserRole).value<ExtraData>();
}
void ProtocolItem::setFolderName(QTreeWidgetItem *item, const QString &folderName)
void ProtocolItem::setExtraData(QTreeWidgetItem *item, const ExtraData &data)
{
item->setData(2, Qt::UserRole, folderName);
}
QString ProtocolItem::filePath(const QTreeWidgetItem *item)
{
return item->toolTip(1);
}
void ProtocolItem::setFilePath(QTreeWidgetItem *item, const QString &filePath)
{
item->setToolTip(1, filePath);
}
QDateTime ProtocolItem::timestamp(const QTreeWidgetItem *item)
{
return item->data(0, Qt::UserRole).toDateTime();
}
void ProtocolItem::setTimestamp(QTreeWidgetItem *item, const QDateTime &timestamp)
{
item->setData(0, Qt::UserRole, timestamp);
}
SyncFileItem::Status ProtocolItem::status(const QTreeWidgetItem *item)
{
return static_cast<SyncFileItem::Status>(item->data(3, Qt::UserRole).toInt());
}
void ProtocolItem::setStatus(QTreeWidgetItem *item, SyncFileItem::Status status)
{
item->setData(3, Qt::UserRole, status);
}
quint64 ProtocolItem::size(const QTreeWidgetItem *item)
{
return item->data(4, Qt::UserRole).toULongLong();
}
void ProtocolItem::setSize(QTreeWidgetItem *item, quint64 size)
{
item->setData(4, Qt::UserRole, size);
item->setData(0, Qt::UserRole, QVariant::fromValue(data));
}
ProtocolItem *ProtocolItem::create(const QString &folder, const SyncFileItem &item)
@ -136,12 +98,16 @@ ProtocolItem *ProtocolItem::create(const QString &folder, const SyncFileItem &it
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(1, item._file);
twitem->setToolTip(3, message);
setTimestamp(twitem, timestamp);
setFilePath(twitem, item._file); // also sets toolTip(1)
setFolderName(twitem, folder);
setStatus(twitem, item._status);
setSize(twitem, item._size);
ProtocolItem::ExtraData data;
data.timestamp = timestamp;
data.path = item._file;
data.folderName = folder;
data.status = item._status;
data.size = item._size;
data.direction = item._direction;
ProtocolItem::setExtraData(twitem, data);
return twitem;
}
@ -151,13 +117,13 @@ SyncJournalFileRecord ProtocolItem::syncJournalRecord(QTreeWidgetItem *item)
auto f = folder(item);
if (!f)
return rec;
f->journalDb()->getFileRecord(filePath(item), &rec);
f->journalDb()->getFileRecord(extraData(item).path, &rec);
return rec;
}
Folder *ProtocolItem::folder(QTreeWidgetItem *item)
{
return FolderMan::instance()->folder(folderName(item));
return FolderMan::instance()->folder(extraData(item).folderName);
}
void ProtocolItem::openContextMenu(QPoint globalPos, QTreeWidgetItem *item, QWidget *parent)
@ -199,10 +165,10 @@ bool ProtocolItem::operator<(const QTreeWidgetItem &other) const
if (column == 0) {
// Items with empty "File" column are larger than others,
// otherwise sort by time (this uses lexicographic ordering)
return std::forward_as_tuple(text(1).isEmpty(), timestamp(this))
< std::forward_as_tuple(other.text(1).isEmpty(), timestamp(&other));
return std::forward_as_tuple(text(1).isEmpty(), extraData(this).timestamp)
< std::forward_as_tuple(other.text(1).isEmpty(), extraData(&other).timestamp);
} else if (column == 4) {
return size(this) < size(&other);
return extraData(this).size < extraData(&other).size;
}
return QTreeWidgetItem::operator<(other);

View File

@ -49,17 +49,24 @@ public:
static ProtocolItem *create(const QString &folder, const SyncFileItem &item);
static QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat);
// accessors for extra data stored in the item
static QString folderName(const QTreeWidgetItem *item);
static void setFolderName(QTreeWidgetItem *item, const QString &folderName);
static QString filePath(const QTreeWidgetItem *item);
static void setFilePath(QTreeWidgetItem *item, const QString &filePath);
static QDateTime timestamp(const QTreeWidgetItem *item);
static void setTimestamp(QTreeWidgetItem *item, const QDateTime &timestamp);
static SyncFileItem::Status status(const QTreeWidgetItem *item);
static void setStatus(QTreeWidgetItem *item, SyncFileItem::Status status);
static quint64 size(const QTreeWidgetItem *item);
static void setSize(QTreeWidgetItem *item, quint64 size);
struct ExtraData
{
ExtraData()
: status(SyncFileItem::NoStatus)
, direction(SyncFileItem::None)
{
}
QString path;
QString folderName;
QDateTime timestamp;
quint64 size = 0;
SyncFileItem::Status status BITFIELD(4);
SyncFileItem::Direction direction BITFIELD(3);
};
static ExtraData extraData(const QTreeWidgetItem *item);
static void setExtraData(QTreeWidgetItem *item, const ExtraData &data);
static SyncJournalFileRecord syncJournalRecord(QTreeWidgetItem *item);
static Folder *folder(QTreeWidgetItem *item);

View File

@ -237,6 +237,9 @@ void SettingsDialog::accountAdded(AccountState *s)
connect(s->account().data(), &Account::accountChangedAvatar, this, &SettingsDialog::slotAccountAvatarChanged);
connect(s->account().data(), &Account::accountChangedDisplayName, this, &SettingsDialog::slotAccountDisplayNameChanged);
// Refresh immediatly when getting online
connect(s, &AccountState::isConnectedChanged, this, &SettingsDialog::slotRefreshActivityAccountStateSender);
slotRefreshActivity(s);
}
@ -379,6 +382,11 @@ QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const Q
return createActionWithIcon(coloredIcon, text, iconPath);
}
void SettingsDialog::slotRefreshActivityAccountStateSender()
{
slotRefreshActivity(qobject_cast<AccountState*>(sender()));
}
void SettingsDialog::slotRefreshActivity(AccountState *accountState)
{
if (accountState) {

View File

@ -59,6 +59,7 @@ public slots:
void showIssuesList(const QString &folderAlias);
void slotSwitchPage(QAction *action);
void slotRefreshActivity(AccountState *accountState);
void slotRefreshActivityAccountStateSender();
void slotAccountAvatarChanged();
void slotAccountDisplayNameChanged();

View File

@ -21,6 +21,7 @@
#include "generalsettings.h"
#include "networksettings.h"
#include "accountsettings.h"
#include "accountstate.h"
#include "creds/abstractcredentials.h"
#include "configfile.h"
#include "progressdispatcher.h"
@ -121,6 +122,7 @@ SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
ConfigFile cfg;
cfg.restoreGeometry(this);
_activitySettings->setNotificationRefreshInterval(cfg.notificationRefreshInterval());
}
void SettingsDialogMac::closeEvent(QCloseEvent *event)
@ -160,6 +162,9 @@ void SettingsDialogMac::accountAdded(AccountState *s)
connect(s->account().data(), &Account::accountChangedAvatar, this, &SettingsDialogMac::slotAccountAvatarChanged);
connect(s->account().data(), &Account::accountChangedDisplayName, this, &SettingsDialogMac::slotAccountDisplayNameChanged);
// Refresh immediatly when getting online
connect(s, &AccountState::isConnectedChanged, this, &SettingsDialogMac::slotRefreshActivityAccountStateSender);
slotRefreshActivity(s);
}
@ -175,6 +180,11 @@ void SettingsDialogMac::accountRemoved(AccountState *s)
_activitySettings->slotRemoveAccount(s);
}
void SettingsDialogMac::slotRefreshActivityAccountStateSender()
{
slotRefreshActivity(qobject_cast<AccountState*>(sender()));
}
void SettingsDialogMac::slotRefreshActivity(AccountState *accountState)
{
if (accountState) {

View File

@ -49,6 +49,7 @@ public slots:
void showActivityPage();
void showIssuesList(const QString &folderAlias);
void slotRefreshActivity(AccountState *accountState);
void slotRefreshActivityAccountStateSender();
private slots:
void accountAdded(AccountState *);

View File

@ -113,6 +113,7 @@ ShareDialog::ShareDialog(QPointer<AccountState> accountState,
label->setWordWrap(true);
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout()->replaceWidget(_ui->shareWidgets, label);
_ui->shareWidgets->hide();
return;
}

View File

@ -58,7 +58,7 @@ static bool isSelfSigned(const QSslCertificate &certificate)
}
QMenu *SslButton::buildCertMenu(QMenu *parent, const QSslCertificate &cert,
const QList<QSslCertificate> &userApproved, int pos)
const QList<QSslCertificate> &userApproved, int pos, const QList<QSslCertificate> &systemCaCertificates)
{
QString cn = QStringList(cert.subjectInfo(QSslCertificate::CommonName)).join(QChar(';'));
QString ou = QStringList(cert.subjectInfo(QSslCertificate::OrganizationalUnitName)).join(QChar(';'));
@ -129,7 +129,7 @@ QMenu *SslButton::buildCertMenu(QMenu *parent, const QSslCertificate &cert,
QString certId = cn.isEmpty() ? ou : cn;
if (QSslConfiguration::systemCaCertificates().contains(cert)) {
if (systemCaCertificates.contains(cert)) {
txt += certId;
} else {
if (isSelfSigned(cert)) {
@ -189,6 +189,10 @@ void SslButton::slotUpdateMenu()
AccountPtr account = _accountState->account();
if (account->isHttp2Supported()) {
_menu->addAction("HTTP/2")->setEnabled(false);
}
if (account->url().scheme() == QLatin1String("https")) {
QString sslVersion = account->_sessionCipher.protocolString()
+ ", " + account->_sessionCipher.authenticationMethod()
@ -232,7 +236,7 @@ void SslButton::slotUpdateMenu()
it.toBack();
int i = 0;
while (it.hasPrevious()) {
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i));
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i, systemCerts));
i++;
}
}

View File

@ -43,7 +43,7 @@ public slots:
private:
QMenu *buildCertMenu(QMenu *parent, const QSslCertificate &cert,
const QList<QSslCertificate> &userApproved, int pos);
const QList<QSslCertificate> &userApproved, int pos, const QList<QSslCertificate> &systemCaCertificates);
QPointer<AccountState> _accountState;
QMenu *_menu;
};

View File

@ -162,7 +162,8 @@ void SyncRunFileLog::start(const QString &folderPath)
void SyncRunFileLog::logItem(const SyncFileItem &item)
{
// don't log the directory items that are in the list
if (item._direction == SyncFileItem::None) {
if (item._direction == SyncFileItem::None
|| item._instruction == CSYNC_INSTRUCTION_IGNORE) {
return;
}
QString ts = QString::fromLatin1(item._responseTimeStamp);

View File

@ -24,8 +24,6 @@ set(libsync_SRCS
wordlist.cpp
bandwidthmanager.cpp
capabilities.cpp
clientproxy.cpp
connectionvalidator.cpp
cookiejar.cpp
discoveryphase.cpp
filesystem.cpp

View File

@ -475,7 +475,7 @@ bool Account::serverVersionUnsupported() const
// not detected yet, assume it is fine.
return false;
}
return serverVersionInt() < makeServerVersion(7, 0, 0);
return serverVersionInt() < makeServerVersion(9, 1, 0);
}
void Account::setServerVersion(const QString &version)

View File

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

View File

@ -300,10 +300,8 @@ void DiscoverySingleDirectoryJob::abort()
}
}
static std::unique_ptr<csync_file_stat_t> propertyMapToFileStat(const QMap<QString, QString> &map)
static void propertyMapToFileStat(const QMap<QString, QString> &map, csync_file_stat_t *file_stat)
{
std::unique_ptr<csync_file_stat_t> file_stat(new csync_file_stat_t);
for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
QString property = it.key();
QString value = it.value();
@ -316,10 +314,13 @@ static std::unique_ptr<csync_file_stat_t> propertyMapToFileStat(const QMap<QStri
} else if (property == "getlastmodified") {
file_stat->modtime = oc_httpdate_parse(value.toUtf8());
} else if (property == "getcontentlength") {
// See #4573, sometimes negative size values are returned
bool ok = false;
qlonglong ll = value.toLongLong(&ok);
if (ok && ll >= 0) {
file_stat->size = ll;
} else {
file_stat->size = 0;
}
} else if (property == "getetag") {
file_stat->etag = Utility::normalizeEtag(value.toUtf8());
@ -346,7 +347,6 @@ static std::unique_ptr<csync_file_stat_t> propertyMapToFileStat(const QMap<QStri
}
}
}
return file_stat;
}
void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, const QMap<QString, QString> &map)
@ -374,12 +374,26 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
file = file.remove(0, 1);
}
std::unique_ptr<csync_file_stat_t> file_stat(propertyMapToFileStat(map));
std::unique_ptr<csync_file_stat_t> file_stat(new csync_file_stat_t);
file_stat->path = file.toUtf8();
if (file_stat->etag.isEmpty()) {
qCCritical(lcDiscovery) << "etag of" << file_stat->path << "is" << file_stat->etag << "This must not happen.";
file_stat->size = -1;
file_stat->modtime = -1;
propertyMapToFileStat(map, file_stat.get());
if (file_stat->type == ItemTypeDirectory)
file_stat->size = 0;
if (file_stat->type == ItemTypeSkip
|| file_stat->size == -1
|| file_stat->modtime == -1
|| file_stat->remotePerm.isNull()
|| file_stat->etag.isEmpty()
|| file_stat->file_id.isEmpty()) {
_error = tr("The server file discovery reply is missing data.");
qCWarning(lcDiscovery)
<< "Missing properties:" << file << file_stat->type << file_stat->size
<< file_stat->modtime << file_stat->remotePerm.toString()
<< file_stat->etag << file_stat->file_id;
}
if (_isExternalStorage && file_stat->remotePerm.hasPermission(RemotePermissions::IsMounted)) {
/* All the entries in a external storage have 'M' in their permission. However, for all
purposes in the desktop client, we only need to know about the mount points.
@ -414,6 +428,10 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithoutErrorSlot()
emit finishedWithError(ERRNO_WRONG_CONTENT, QLatin1String("Server error: PROPFIND reply is not XML formatted!"));
deleteLater();
return;
} else if (!_error.isEmpty()) {
emit finishedWithError(ERRNO_WRONG_CONTENT, _error);
deleteLater();
return;
}
emit etag(_firstEtag);
emit etagConcatenation(_etagConcatenation);
@ -470,8 +488,7 @@ void DiscoveryMainThread::doOpendirSlot(const QString &subPath, DiscoveryDirecto
fullPath.chop(1);
}
// emit _discoveryJob->folderDiscovered(false, subPath);
_discoveryJob->update_job_update_callback(false, subPath.toUtf8(), _discoveryJob);
_discoveryJob->update_job_update_callback(/*local=*/false, subPath.toUtf8(), _discoveryJob);
// Result gets written in there
_currentDiscoveryDirectoryResult = r;

View File

@ -91,6 +91,8 @@ private:
bool _isRootPath;
// If this directory is an external storage (The first item has 'M' in its permission)
bool _isExternalStorage;
// If set, the discovery will finish with an error
QString _error;
QPointer<LsColJob> _lsColJob;
public:

View File

@ -286,60 +286,6 @@ void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &error
}
}
/**
* For delete or remove, check that we are not removing from a shared directory.
* If we are, try to restore the file
*
* Return true if the problem is handled.
*/
bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QString &msg)
{
PropagateItemJob *newJob = NULL;
if (httpStatusCode == 403 && propagator()->isInSharedDirectory(_item->_file)) {
if (!_item->isDirectory()) {
SyncFileItemPtr downloadItem(new SyncFileItem(*_item));
if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW
|| downloadItem->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE) {
// don't try to recover pushing new files
return false;
} else if (downloadItem->_instruction == CSYNC_INSTRUCTION_SYNC) {
// we modified the file locally, just create a conflict then
downloadItem->_instruction = CSYNC_INSTRUCTION_CONFLICT;
// HACK to avoid continuation: See task #1448: We do not know the _modtime from the
// server, at this point, so just set the current one. (rather than the one locally)
downloadItem->_modtime = Utility::qDateTimeToTime_t(QDateTime::currentDateTimeUtc());
} else {
// the file was removed or renamed, just recover the old one
downloadItem->_instruction = CSYNC_INSTRUCTION_SYNC;
}
downloadItem->_direction = SyncFileItem::Down;
newJob = new PropagateDownloadFile(propagator(), downloadItem);
} else {
// Directories are harder to recover.
// But just re-create the directory, next sync will be able to recover the files
SyncFileItemPtr mkdirItem(new SyncFileItem(*_item));
mkdirItem->_instruction = CSYNC_INSTRUCTION_NEW;
mkdirItem->_direction = SyncFileItem::Down;
newJob = new PropagateLocalMkdir(propagator(), mkdirItem);
// Also remove the inodes and fileid from the db so no further renames are tried for
// this item.
propagator()->_journal->avoidRenamesOnNextSync(_item->_file);
propagator()->_anotherSyncNeeded = true;
}
if (newJob) {
newJob->setRestoreJobMsg(msg);
_restoreJob.reset(newJob);
connect(_restoreJob.data(), &PropagatorJob::finished,
this, &PropagateItemJob::slotRestoreJobFinished);
QMetaObject::invokeMethod(newJob, "start");
}
return true;
}
return false;
}
void PropagateItemJob::slotRestoreJobFinished(SyncFileItem::Status status)
{
QString msg;
@ -559,23 +505,6 @@ void OwncloudPropagator::setSyncOptions(const SyncOptions &syncOptions)
_chunkSize = syncOptions._initialChunkSize;
}
// ownCloud server < 7.0 did not had permissions so we need some other euristics
// to detect wrong doing in a Shared directory
bool OwncloudPropagator::isInSharedDirectory(const QString &file)
{
bool re = false;
if (_remoteFolder.startsWith(QLatin1String("Shared"))) {
// The Shared directory is synced as its own sync connection
re = true;
} else {
if (file.startsWith("Shared/") || file == "Shared") {
// The whole ownCloud is synced and Shared is always a top dir
re = true;
}
}
return re;
}
bool OwncloudPropagator::localFileNameClash(const QString &relFile)
{
bool re = false;
@ -588,8 +517,7 @@ bool OwncloudPropagator::localFileNameClash(const QString &relFile)
re = false;
qCWarning(lcPropagator) << "No valid fileinfo";
} else {
// Need to normalize to composited form because of
// https://bugreports.qt-project.org/browse/QTBUG-39622
// Need to normalize to composited form because of QTBUG-39622/QTBUG-55896
const QString cName = fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_C);
bool equal = (file == cName);
re = (!equal && !cName.endsWith(relFile, Qt::CaseSensitive));

View File

@ -156,9 +156,7 @@ class PropagateItemJob : public PropagatorJob
{
Q_OBJECT
protected:
void done(SyncFileItem::Status status, const QString &errorString = QString());
bool checkForProblemsWithShared(int httpStatusCode, const QString &msg);
virtual void done(SyncFileItem::Status status, const QString &errorString = QString());
/*
* set a custom restore job message that is used if the restore job succeeded.
@ -436,8 +434,6 @@ public:
/* The maximum number of active jobs in parallel */
int hardMaximumActiveJob();
bool isInSharedDirectory(const QString &file);
/** Check whether a download would clash with an existing file
* in filesystems that are only case-preserving.
*/

View File

@ -139,7 +139,8 @@ void ProgressInfo::reset()
_status = Starting;
_currentItems.clear();
_currentDiscoveredFolder.clear();
_currentDiscoveredRemoteFolder.clear();
_currentDiscoveredLocalFolder.clear();
_sizeProgress = Progress();
_fileProgress = Progress();
_totalSizeOfCompletedJobs = 0;

View File

@ -181,7 +181,8 @@ public:
SyncFileItem _lastCompletedItem;
// Used during local and remote update phase
QString _currentDiscoveredFolder;
QString _currentDiscoveredRemoteFolder;
QString _currentDiscoveredLocalFolder;
void setProgressComplete(const SyncFileItem &item);
@ -295,6 +296,11 @@ signals:
*/
void syncError(const QString &folder, const QString &message, ErrorCategory category);
/**
* @brief Emitted for a folder when a sync is done, listing all pending conflicts
*/
void folderConflicts(const QString &folder, const QStringList &conflictPaths);
protected:
void setProgressInfo(const QString &folder, const ProgressInfo &progress);

View File

@ -111,11 +111,6 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
_item->_httpErrorCode = httpStatus;
if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
if (checkForProblemsWithShared(_item->_httpErrorCode,
tr("The file has been removed from a read only share. It was restored."))) {
return;
}
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
&propagator()->_anotherSyncNeeded);
done(status, _job->errorString());

View File

@ -88,24 +88,6 @@ void PropagateRemoteMove::start()
finalize();
return;
}
if (_item->_file == QLatin1String("Shared")) {
// Before owncloud 7, there was no permissions system. At the time all the shared files were
// in a directory called "Shared" and were not supposed to be moved, otherwise bad things happened
QString versionString = propagator()->account()->serverVersion();
if (versionString.contains('.') && versionString.split('.')[0].toInt() < 7) {
QString originalFile(propagator()->getFilePath(QLatin1String("Shared")));
emit propagator()->touchedFile(originalFile);
emit propagator()->touchedFile(targetFile);
QString renameError;
if (FileSystem::rename(targetFile, originalFile, &renameError)) {
done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name."));
} else {
done(SyncFileItem::NormalError, tr("This folder must not be renamed. Please name it back to Shared."));
}
return;
}
}
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
+ propagator()->account()->davPath() + propagator()->_remoteFolder + _item->_renameTarget);
@ -137,11 +119,6 @@ void PropagateRemoteMove::slotMoveJobFinished()
_item->_httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (err != QNetworkReply::NoError) {
if (checkForProblemsWithShared(_item->_httpErrorCode,
tr("The file was renamed but is part of a read only share. The original file was restored."))) {
return;
}
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
&propagator()->_anotherSyncNeeded);
done(status, _job->errorString());

View File

@ -529,7 +529,6 @@ void PropagateUploadFileCommon::slotPollFinished()
propagator()->_activeJobList.removeOne(this);
if (job->_item->_status != SyncFileItem::Success) {
_finished = true;
done(job->_item->_status, job->_item->_errorString);
return;
}
@ -537,6 +536,12 @@ void PropagateUploadFileCommon::slotPollFinished()
finalize();
}
void PropagateUploadFileCommon::done(SyncFileItem::Status status, const QString &errorString)
{
_finished = true;
PropagateItemJob::done(status, errorString);
}
void PropagateUploadFileCommon::checkResettingErrors()
{
if (_item->_httpErrorCode == 412
@ -622,7 +627,6 @@ void PropagateUploadFileCommon::abort(PropagatorJob::AbortType abortType)
// This function is used whenever there is an error occuring and jobs might be in progress
void PropagateUploadFileCommon::abortWithError(SyncFileItem::Status status, const QString &error)
{
_finished = true;
abort(AbortType::Synchronous);
done(status, error);
}
@ -671,9 +675,6 @@ QMap<QByteArray, QByteArray> PropagateUploadFileCommon::headers()
void PropagateUploadFileCommon::finalize()
{
qDebug() << "Finalizing the upload. Check later if this is encrypted";
_finished = true;
// Update the quota, if known
auto quotaIt = propagator()->_folderQuota.find(QFileInfo(_item->_file).path());
if (quotaIt != propagator()->_folderQuota.end())

View File

@ -279,6 +279,8 @@ private slots:
void slotPollFinished();
protected:
void done(SyncFileItem::Status status, const QString &errorString = QString()) override;
/**
* Prepares the abort e.g. connects proper signals and slots
* to the subjobs to abort asynchronously

View File

@ -276,6 +276,7 @@ void PropagateUploadFileNG::startNextChunk()
if (_currentChunkSize == 0) {
Q_ASSERT(_jobs.isEmpty()); // There should be no running job anymore
_finished = true;
// Finish with a MOVE
// If we changed the file name, we must store the changed filename in the remote folder, not the original one.
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
@ -394,19 +395,12 @@ void PropagateUploadFileNG::slotPutFinished()
<< propagator()->_chunkSize << "bytes";
}
bool finished = _sent == _fileToUpload._size;
_finished = _sent == _item->_size;
// Check if the file still exists
/* Check if the file still exists,
* but we could be operating in a temporary file, so check both if
* the file to upload is different than the file on disk
*/
const QString fileToUploadPath = _fileToUpload._path;
const QString fullFilePath(propagator()->getFilePath(_item->_file));
bool fileExists = fileToUploadPath == fullFilePath ? FileSystem::fileExists(fullFilePath)
: (FileSystem::fileExists(fileToUploadPath) && FileSystem::fileExists(fullFilePath));
if (!fileExists) {
if (!finished) {
if (!FileSystem::fileExists(fullFilePath)) {
if (!_finished) {
abortWithError(SyncFileItem::SoftError, tr("The local file was removed during sync."));
return;
} else {
@ -417,13 +411,13 @@ void PropagateUploadFileNG::slotPutFinished()
// Check whether the file changed since discovery - this acts on the original file.
if (!FileSystem::verifyFileUnchanged(fullFilePath, _item->_size, _item->_modtime)) {
propagator()->_anotherSyncNeeded = true;
if (!finished) {
if (!_finished) {
abortWithError(SyncFileItem::SoftError, tr("Local file changed during sync."));
return;
}
}
if (!finished) {
if (!_finished) {
// Deletes an existing blacklist entry on successful chunk upload
if (_item->_hasBlacklistEntry) {
propagator()->_journal->wipeErrorBlacklistEntry(_item->_file);

View File

@ -197,28 +197,21 @@ void PropagateUploadFileV1::slotPutFinished()
return;
}
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QNetworkReply::NetworkError err = job->reply()->error();
if (err != QNetworkReply::NoError) {
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (checkForProblemsWithShared(_item->_httpErrorCode,
tr("The file was edited locally but is part of a read only share. "
"It is restored and your edit is in the conflict file."))) {
return;
}
commonErrorHandling(job);
return;
}
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// The server needs some time to process the request and provide us with a poll URL
if (_item->_httpErrorCode == 202) {
_finished = true;
QString path = QString::fromUtf8(job->reply()->rawHeader("OC-Finish-Poll"));
if (path.isEmpty()) {
done(SyncFileItem::NormalError, tr("Poll URL missing"));
return;
}
_finished = true;
startPollJob(path);
return;
}
@ -233,19 +226,15 @@ void PropagateUploadFileV1::slotPutFinished()
// yet, the upload can be stopped and an error can be displayed, because
// the server hasn't registered the new file yet.
QByteArray etag = getEtagFromReply(job->reply());
bool finished = etag.length() > 0;
_finished = etag.length() > 0;
/* Check if the file still exists,
* but we could be operating in a temporary file, so check both if
* the file to upload is different than the file on disk
*/
const QString fileToUploadPath = _fileToUpload._path;
const QString fullFilePath(propagator()->getFilePath(_item->_file));
bool fileExists = fileToUploadPath == fullFilePath ? FileSystem::fileExists(fullFilePath)
: (FileSystem::fileExists(fileToUploadPath) && FileSystem::fileExists(fullFilePath));
if (!fileExists) {
if (!finished) {
if (!FileSystem::fileExists(fullFilePath)) {
if (!_finished) {
abortWithError(SyncFileItem::SoftError, tr("The local file was removed during sync."));
return;
} else {
@ -256,7 +245,7 @@ void PropagateUploadFileV1::slotPutFinished()
// Check whether the file changed since discovery. the file check here is the original and not the temprary.
if (!FileSystem::verifyFileUnchanged(fullFilePath, _item->_size, _item->_modtime)) {
propagator()->_anotherSyncNeeded = true;
if (!finished) {
if (!_finished) {
abortWithError(SyncFileItem::SoftError, tr("Local file changed during sync."));
// FIXME: the legacy code was retrying for a few seconds.
// and also checking that after the last chunk, and removed the file in case of INSTRUCTION_NEW
@ -264,14 +253,13 @@ void PropagateUploadFileV1::slotPutFinished()
}
}
if (!finished) {
if (!_finished) {
// Proceed to next chunk.
if (_currentChunk >= _chunkCount) {
if (!_jobs.empty()) {
// just wait for the other job to finish.
return;
}
_finished = true;
done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag was present)"));
return;
}
@ -301,9 +289,8 @@ void PropagateUploadFileV1::slotPutFinished()
startNextChunk();
return;
}
// the following code only happens after all chunks were uploaded.
_finished = true;
// the file id should only be empty for new files up- or downloaded
QByteArray fid = job->reply()->rawHeader("OC-FileID");
if (!fid.isEmpty()) {
@ -323,6 +310,7 @@ void PropagateUploadFileV1::slotPutFinished()
qCWarning(lcPropagateUpload) << "Server does not support X-OC-MTime" << job->reply()->rawHeader("X-OC-MTime");
// Well, the mtime was not set
done(SyncFileItem::SoftError, "Server does not support X-OC-MTime");
return;
}
finalize();

View File

@ -67,7 +67,7 @@ bool PropagateLocalRemove::removeRecursively(const QString &path)
bool ok;
// The use of isSymLink here is okay:
// we never want to go into this branch for .lnk files
bool isDir = fi.isDir() && !fi.isSymLink();
bool isDir = fi.isDir() && !fi.isSymLink() && !FileSystem::isJunction(fi.absoluteFilePath());
if (isDir) {
ok = removeRecursively(path + QLatin1Char('/') + di.fileName()); // recursive
} else {

View File

@ -120,35 +120,11 @@ QString SyncEngine::csyncErrorToString(CSYNC_STATUS err)
errStr = tr("Success.");
break;
case CSYNC_STATUS_STATEDB_LOAD_ERROR:
errStr = tr("CSync failed to load or create the journal file. "
errStr = tr("Failed to load or create the journal file. "
"Make sure you have read and write permissions in the local sync folder.");
break;
case CSYNC_STATUS_STATEDB_CORRUPTED:
errStr = tr("CSync failed to load the journal file. The journal file is corrupted.");
break;
case CSYNC_STATUS_NO_MODULE:
errStr = tr("<p>The %1 plugin for csync could not be loaded.<br/>Please verify the installation!</p>").arg(qApp->applicationName());
break;
case CSYNC_STATUS_PARAM_ERROR:
errStr = tr("CSync fatal parameter error.");
break;
case CSYNC_STATUS_UPDATE_ERROR:
errStr = tr("CSync processing step update failed.");
break;
case CSYNC_STATUS_RECONCILE_ERROR:
errStr = tr("CSync processing step reconcile failed.");
break;
case CSYNC_STATUS_PROXY_AUTH_ERROR:
errStr = tr("CSync could not authenticate at the proxy.");
break;
case CSYNC_STATUS_LOOKUP_ERROR:
errStr = tr("CSync failed to lookup proxy or server.");
break;
case CSYNC_STATUS_SERVER_AUTH_ERROR:
errStr = tr("CSync failed to authenticate at the %1 server.").arg(qApp->applicationName());
break;
case CSYNC_STATUS_CONNECT_ERROR:
errStr = tr("CSync failed to connect to the network.");
errStr = tr("Discovery step failed.");
break;
case CSYNC_STATUS_TIMEOUT:
errStr = tr("A network connection timeout happened.");
@ -157,16 +133,16 @@ QString SyncEngine::csyncErrorToString(CSYNC_STATUS err)
errStr = tr("A HTTP transmission error happened.");
break;
case CSYNC_STATUS_PERMISSION_DENIED:
errStr = tr("CSync failed due to unhandled permission denied.");
errStr = tr("Permission denied.");
break;
case CSYNC_STATUS_NOT_FOUND:
errStr = tr("CSync failed to access") + " "; // filename gets added.
errStr = tr("File or directory not found:") + " "; // filename gets added.
break;
case CSYNC_STATUS_FILE_EXISTS:
errStr = tr("CSync tried to create a folder that already exists.");
errStr = tr("Tried to create a folder that already exists.");
break;
case CSYNC_STATUS_OUT_OF_SPACE:
errStr = tr("CSync: No space on %1 server available.").arg(qApp->applicationName());
errStr = tr("No space on %1 server available.").arg(qApp->applicationName());
break;
case CSYNC_STATUS_UNSUCCESSFUL:
errStr = tr("CSync unspecified error.");
@ -272,13 +248,29 @@ bool SyncEngine::checkErrorBlacklisting(SyncFileItem &item)
return true;
}
static bool isFileTransferInstruction(csync_instructions_e instruction)
{
return instruction == CSYNC_INSTRUCTION_CONFLICT
|| instruction == CSYNC_INSTRUCTION_NEW
|| instruction == CSYNC_INSTRUCTION_SYNC
|| instruction == CSYNC_INSTRUCTION_TYPE_CHANGE;
}
static bool isFileModifyingInstruction(csync_instructions_e instruction)
{
return isFileTransferInstruction(instruction)
|| instruction == CSYNC_INSTRUCTION_RENAME
|| instruction == CSYNC_INSTRUCTION_REMOVE;
}
void SyncEngine::deleteStaleDownloadInfos(const SyncFileItemVector &syncItems)
{
// Find all downloadinfo paths that we want to preserve.
QSet<QString> download_file_paths;
foreach (const SyncFileItemPtr &it, syncItems) {
if (it->_direction == SyncFileItem::Down
&& it->_type == ItemTypeFile) {
&& it->_type == ItemTypeFile
&& isFileTransferInstruction(it->_instruction)) {
download_file_paths.insert(it->_file);
}
}
@ -299,7 +291,8 @@ void SyncEngine::deleteStaleUploadInfos(const SyncFileItemVector &syncItems)
QSet<QString> upload_file_paths;
foreach (const SyncFileItemPtr &it, syncItems) {
if (it->_direction == SyncFileItem::Up
&& it->_type == ItemTypeFile) {
&& it->_type == ItemTypeFile
&& isFileTransferInstruction(it->_instruction)) {
upload_file_paths.insert(it->_file);
}
}
@ -368,16 +361,6 @@ void SyncEngine::conflictRecordMaintenance()
}
}
int SyncEngine::treewalkLocal(csync_file_stat_t *file, csync_file_stat_t *other, void *data)
{
return static_cast<SyncEngine *>(data)->treewalkFile(file, other, false);
}
int SyncEngine::treewalkRemote(csync_file_stat_t *file, csync_file_stat_t *other, void *data)
{
return static_cast<SyncEngine *>(data)->treewalkFile(file, other, true);
}
/**
* The main function in the post-reconcile phase.
*
@ -393,26 +376,38 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
if (!file)
return -1;
QTextCodec::ConverterState utf8State;
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
ASSERT(codec);
QString fileUtf8 = codec->toUnicode(file->path, file->path.size(), &utf8State);
QString renameTarget;
QString key = fileUtf8;
auto instruction = file->instruction;
if (utf8State.invalidChars > 0 || utf8State.remainingChars > 0) {
qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence: " << file->path;
instruction = CSYNC_INSTRUCTION_IGNORE;
} else {
renameTarget = codec->toUnicode(file->rename_path, file->rename_path.size(), &utf8State);
if (utf8State.invalidChars > 0 || utf8State.remainingChars > 0) {
// Decode utf8 path and rename_path QByteArrays to QStrings
QString fileUtf8;
QString renameTarget;
bool utf8DecodeError = false;
{
const auto toUnicode = [](QByteArray utf8, QString *result) {
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
ASSERT(codec);
QTextCodec::ConverterState state;
*result = codec->toUnicode(utf8, utf8.size(), &state);
return !(state.invalidChars > 0 || state.remainingChars > 0);
};
if (!toUnicode(file->path, &fileUtf8)) {
qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence: " << file->path;
instruction = CSYNC_INSTRUCTION_IGNORE;
utf8DecodeError = true;
}
if (!toUnicode(file->rename_path, &renameTarget)) {
qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence in the rename_path: " << file->path << file->rename_path;
instruction = CSYNC_INSTRUCTION_IGNORE;
utf8DecodeError = true;
}
if (instruction == CSYNC_INSTRUCTION_RENAME) {
key = renameTarget;
}
}
// key is the handle that the SyncFileItem will have in the map.
QString key = fileUtf8;
if (instruction == CSYNC_INSTRUCTION_RENAME) {
key = renameTarget;
}
// Gets a default-constructed SyncFileItemPtr or the one from the first walk (=local walk)
@ -561,7 +556,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
/* No error string */
}
if (item->_instruction == CSYNC_INSTRUCTION_IGNORE && (utf8State.invalidChars > 0 || utf8State.remainingChars > 0)) {
if (item->_instruction == CSYNC_INSTRUCTION_IGNORE && utf8DecodeError) {
item->_status = SyncFileItem::NormalError;
//item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Filename encoding is not valid");
@ -664,7 +659,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
break;
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR:
dir = SyncFileItem::None;
break;
@ -692,6 +686,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
case CSYNC_INSTRUCTION_NEW:
case CSYNC_INSTRUCTION_EVAL:
case CSYNC_INSTRUCTION_STAT_ERROR:
case CSYNC_INSTRUCTION_IGNORE:
default:
dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
break;
@ -742,7 +737,7 @@ void SyncEngine::handleSyncError(CSYNC *ctx, const char *state)
if (CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_ABORTED)) {
qCInfo(lcEngine) << "Update phase was aborted by user!";
} else if (CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_SERVICE_UNAVAILABLE) || CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_CONNECT_ERROR)) {
} else if (CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_SERVICE_UNAVAILABLE)) {
emit csyncUnavailable();
} else {
csyncError(errStr);
@ -844,7 +839,11 @@ void SyncEngine::startSync()
_excludedFiles->setExcludeConflictFiles(!_account->capabilities().uploadConflictFiles());
_csync_ctx->read_remote_from_db = true;
_lastLocalDiscoveryStyle = _csync_ctx->local_discovery_style;
_lastLocalDiscoveryStyle = _localDiscoveryStyle;
_csync_ctx->should_discover_locally_fn = [this](const QByteArray &path) {
return shouldDiscoverLocally(path);
};
bool ok;
auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
@ -917,9 +916,18 @@ void SyncEngine::startSync()
QMetaObject::invokeMethod(discoveryJob, "start", Qt::QueuedConnection);
}
void SyncEngine::slotFolderDiscovered(bool /*local*/, const QString &folder)
void SyncEngine::slotFolderDiscovered(bool local, const QString &folder)
{
_progressInfo->_currentDiscoveredFolder = folder;
// Currently remote and local discovery never run in parallel
// Note: Currently this slot is only called occasionally! See the throttling
// in DiscoveryJob::update_job_update_callback.
if (local) {
_progressInfo->_currentDiscoveredLocalFolder = folder;
_progressInfo->_currentDiscoveredRemoteFolder.clear();
} else {
_progressInfo->_currentDiscoveredRemoteFolder = folder;
_progressInfo->_currentDiscoveredLocalFolder.clear();
}
emit transmissionProgress(*_progressInfo);
}
@ -956,7 +964,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
_journal->commitIfNeededAndStartNewTransaction("Post discovery");
}
_progressInfo->_currentDiscoveredFolder.clear();
_progressInfo->_currentDiscoveredRemoteFolder.clear();
_progressInfo->_currentDiscoveredLocalFolder.clear();
_progressInfo->_status = ProgressInfo::Reconcile;
emit transmissionProgress(*_progressInfo);
@ -976,11 +985,11 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
_temporarilyUnavailablePaths.clear();
_renamedFolders.clear();
if (csync_walk_local_tree(_csync_ctx.data(), &treewalkLocal, 0) < 0) {
if (csync_walk_local_tree(_csync_ctx.data(), [this](csync_file_stat_t *f, csync_file_stat_t *o) { return treewalkFile(f, o, false); } ) < 0) {
qCWarning(lcEngine) << "Error in local treewalk.";
walkOk = false;
}
if (walkOk && csync_walk_remote_tree(_csync_ctx.data(), &treewalkRemote, 0) < 0) {
if (walkOk && csync_walk_remote_tree(_csync_ctx.data(), [this](csync_file_stat_t *f, csync_file_stat_t *o) { return treewalkFile(f, o, true); } ) < 0) {
qCWarning(lcEngine) << "Error in remote treewalk.";
}
@ -1010,7 +1019,9 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
if (!invalidFilenamePattern.isEmpty()) {
const QRegExp invalidFilenameRx(invalidFilenamePattern);
for (auto it = syncItems.begin(); it != syncItems.end(); ++it) {
if ((*it)->_direction == SyncFileItem::Up && (*it)->destination().contains(invalidFilenameRx)) {
if ((*it)->_direction == SyncFileItem::Up
&& isFileModifyingInstruction((*it)->_instruction)
&& (*it)->destination().contains(invalidFilenameRx)) {
(*it)->_errorString = tr("File name contains at least one invalid character");
(*it)->_instruction = CSYNC_INSTRUCTION_IGNORE;
}
@ -1058,6 +1069,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
// Re-init the csync context to free memory
_csync_ctx->reinitialize();
_localDiscoveryPaths.clear();
// To announce the beginning of the sync
emit aboutToPropagate(syncItems);
@ -1199,6 +1211,8 @@ void SyncEngine::finalize(bool success)
_temporarilyUnavailablePaths.clear();
_renamedFolders.clear();
_uniqueErrors.clear();
_localDiscoveryPaths.clear();
_localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
_clearTouchedFilesTimer.start();
}
@ -1236,7 +1250,8 @@ void SyncEngine::checkForPermission(SyncFileItemVector &syncItems)
SyncFileItemPtr needle;
for (SyncFileItemVector::iterator it = syncItems.begin(); it != syncItems.end(); ++it) {
if ((*it)->_direction != SyncFileItem::Up) {
if ((*it)->_direction != SyncFileItem::Up
|| !isFileModifyingInstruction((*it)->_instruction)) {
// Currently we only check server-side permissions
continue;
}
@ -1605,8 +1620,32 @@ AccountPtr SyncEngine::account() const
void SyncEngine::setLocalDiscoveryOptions(LocalDiscoveryStyle style, std::set<QByteArray> dirs)
{
_csync_ctx->local_discovery_style = style;
_csync_ctx->locally_touched_dirs = std::move(dirs);
_localDiscoveryStyle = style;
_localDiscoveryPaths = std::move(dirs);
}
bool SyncEngine::shouldDiscoverLocally(const QByteArray &path) const
{
if (_localDiscoveryStyle == LocalDiscoveryStyle::FilesystemOnly)
return true;
auto it = _localDiscoveryPaths.lower_bound(path);
if (it == _localDiscoveryPaths.end() || !it->startsWith(path))
return false;
// maybe an exact match or an empty path?
if (it->size() == path.size() || path.isEmpty())
return true;
// check for a prefix + / match
forever {
if (it->size() > path.size() && it->at(path.size()) == '/')
return true;
++it;
if (it == _localDiscoveryPaths.end() || !it->startsWith(path))
return false;
}
return false;
}
void SyncEngine::abort()

View File

@ -103,7 +103,7 @@ public:
/**
* Control whether local discovery should read from filesystem or db.
*
* If style is Partial, the paths is a set of file paths relative to
* If style is DatabaseAndFilesystem, dirs a set of file paths relative to
* the synced folder. All the parent directories of these paths will not
* be read from the db and scanned on the filesystem.
*
@ -113,6 +113,15 @@ public:
*/
void setLocalDiscoveryOptions(LocalDiscoveryStyle style, std::set<QByteArray> dirs = {});
/**
* Returns whether the given folder-relative path should be locally discovered
* given the local discovery options.
*
* Example: If path is 'foo/bar' and style is DatabaseAndFilesystem and dirs contains
* 'foo/bar/touched_file', then the result will be true.
*/
bool shouldDiscoverLocally(const QByteArray &path) const;
/** Access the last sync run's local discovery style */
LocalDiscoveryStyle lastLocalDiscoveryStyle() const { return _lastLocalDiscoveryStyle; }
@ -194,8 +203,6 @@ private:
QString journalDbFilePath() const;
static int treewalkLocal(csync_file_stat_t *file, csync_file_stat_t *other, void *);
static int treewalkRemote(csync_file_stat_t *file, csync_file_stat_t *other, void *);
int treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other, bool);
bool checkErrorBlacklisting(SyncFileItem &item);
@ -301,7 +308,9 @@ private:
QSet<QString> _uniqueErrors;
/** The kind of local discovery the last sync run used */
LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::DatabaseAndFilesystem;
LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
LocalDiscoveryStyle _localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
std::set<QByteArray> _localDiscoveryPaths;
};
}

View File

@ -185,10 +185,8 @@ void SyncResult::processCompletedItem(const SyncFileItemPtr &item)
// nothing.
break;
}
} else if (item->_direction == SyncFileItem::None) {
if (item->_instruction == CSYNC_INSTRUCTION_IGNORE) {
_foundFilesNotSynced = true;
}
} else if (item->_instruction == CSYNC_INSTRUCTION_IGNORE) {
_foundFilesNotSynced = true;
}
}
}

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