Comparar commits
37 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| eaeed08544 | |||
| f1e2e42d99 | |||
| 3e1690ff7a | |||
| 826a675f32 | |||
| 323ebf9bf2 | |||
| e4bf3ec19a | |||
| f2721aff1d | |||
| 29bd8658bb | |||
| 8b9ca63eeb | |||
| 6f1b03c560 | |||
| 3bd3ffb8e2 | |||
| a810d69daa | |||
| 8496817db2 | |||
| 3d06f4b7c9 | |||
| b228488eb7 | |||
| 907918dca3 | |||
| 5ffaf3a90f | |||
| 1040e7b57b | |||
| 65c49e1de6 | |||
| 4abaee7736 | |||
| 3cdcd8dea0 | |||
| cb19ebc9e3 | |||
| 37adaa7872 | |||
| 9d93afb2a1 | |||
| 7c24ed769e | |||
| 65110f7a91 | |||
| c33abd468d | |||
| 584b205bd5 | |||
| b75f50d62c | |||
| 14457e93e6 | |||
| 9c0ecad420 | |||
| 85b5fdb3d3 | |||
| f2c6669224 | |||
| d8f9bf3a0b | |||
| d5fa8faa91 | |||
| d1a1b95926 | |||
| ee2a67e332 |
@@ -136,13 +136,6 @@ if(OWNCLOUD_RESTORE_RENAME)
|
||||
add_definitions(-DOWNCLOUD_RESTORE_RENAME=1)
|
||||
endif()
|
||||
|
||||
# Disable shibboleth.
|
||||
# So the client can be built without QtWebKit
|
||||
option(NO_SHIBBOLETH "Build without Shibboleth support. Allow to build the client without QtWebKit" OFF)
|
||||
if(NO_SHIBBOLETH)
|
||||
message("Compiling without shibboleth")
|
||||
add_definitions(-DNO_SHIBBOLETH=1)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set( SOCKETAPI_TEAM_IDENTIFIER_PREFIX "" CACHE STRING "SocketApi prefix (including a following dot) that must match the codesign key's TeamIdentifier/Organizational Unit" )
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.2.4 (release 2016-09-27)
|
||||
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
||||
* Selective Sync: Fix HTTP request loop and show error in view (#5154)
|
||||
* ConnectionValidator: properly handle error in status.php request (#5188)
|
||||
* Discovery: Set thread priority to low (#5017)
|
||||
* ExcludeFiles: Fix when the folder casing is not the same in the settings and in the FS
|
||||
* ShareLink: Ensure the password line edit is enabled (#5117)
|
||||
|
||||
version 2.2.3 (release 2016-08-08)
|
||||
* SyncEngine: Fix detection of backup (#5104)
|
||||
* Fix bug with overriding URL in config (#5016)
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
set( MIRALL_VERSION_MAJOR 2 )
|
||||
set( MIRALL_VERSION_MINOR 3 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_MINOR 2 )
|
||||
set( MIRALL_VERSION_PATCH 4 )
|
||||
set( MIRALL_VERSION_YEAR 2016 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "git") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
@@ -33,11 +33,11 @@ StrCpy $UNINSTALL_MESSAGEBOX "Ez dirudi ${APPLICATION_NAME} '$INSTDIR'.$ direkto
|
||||
StrCpy $UNINSTALL_ABORT "Desinstalazioak erabiltzaileak bertan behera utzi du"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Abiarazle Bizkorreko Lasterbidea (E/E)"
|
||||
StrCpy $INIT_NO_DESKTOP "Mahaigaineko Lasterbidea (dagoena berridazten du)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Ezin izan da goratu, errorea:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Instalatzaileak administratzaile baimenak behar ditu, saiatu berriro"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "Instalatzailea dagoeneko martxan da."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Desinstalatzaile honek administratzaile baimenak behar ditu, saiatu berriro"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Saioa hasteko zerbitzua ez dago martxan, bertan behera uzten!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Desinstalatzailea dagoeneko martxan da."
|
||||
StrCpy $SectionGroup_Shortcuts "Lasterbideak"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -30,7 +30,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Z
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Zapisuji odinstal tor"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Zapisuji instal tor do registr…"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "DokonŸeno"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Nezd se, §e ${APPLICATION_NAME} je nainstalov na v adres ýi '$INSTDIR'.$\n$\nChcete pokraŸovat (nedoporuŸuje se)?"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Nezd se, §e ${APPLICATION_NAME} je nainstalov na ve slo§ce '$INSTDIR'.$\n$\nChcete pokraŸovat (nedoporuŸuje se)?"
|
||||
StrCpy $UNINSTALL_ABORT "Odinstalace zruçena u§ivatelem"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Z stupce rychl‚ho spuçtØn¡ (nen¡ k dispozici)"
|
||||
StrCpy $INIT_NO_DESKTOP "Z stupce na ploçe (pýep¡çe existuj¡c¡)"
|
||||
|
||||
@@ -9,7 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "インストール済"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} のインストール方法を選択する"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} の最新バージョンがすでにインストールされています。$\n旧バージョンのインストールはお勧めしません。旧バージョンのインストールが本当に必要な場合は、まず最新バージョンをアンインストールしてから、旧バージョンをインストールしてください。$\nオペレーションを選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} がすでにインストールされています。$\n$\n実行したい操作を選択して、次へをクリックしてください。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} が既にインストールされています。$\n$\n実行したい操作を選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "追加/再インストールコンポーネント"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} をアンインストール"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} をアンインストール"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de lançamento"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Encontrados ${APPLICATION_EXECUTABLE} processo(s) em execução que precisa(m) de ser interrompido(s).$\nDeseja que o instalador o(s) termine por si?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos de ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado nenhum processo para terminar!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Está instalada no sistema uma versão antiga de ${APPLICATION_NAME}. É recomendado que desinstale a versão atual antes de instalar a mais recente. Selecione a operação que deseja executar e clique em $\"Seguinte$\" para continuar."
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Existem ${APPLICATION_EXECUTABLE} processo(s) em execução que precisa(m) de ser interrompido(s).$\nDeseja que o instalador o(s) termine automaticamente?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado o processo a terminar!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Uma versão antiga de ${APPLICATION_NAME} está instalada no sistema. É recomendado que você desinstale a versão atual antes de instalar a mais recente. Selecione a operação que deseja executar e clique em $\"Avançar$\" para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Não desinstale"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Já instalado"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Escolha como pretende instalar ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Uma versão mais recente da aplicação ${APPLICATION_NAME} já está instalada! Não é recomendada a instalação de uma versão mais antiga. Se realmente deseja instalar esta versão, aconselha-se a desinstalação da versão atual primeiro. Selecione a operação que deseja executar e clique em Avançar para continuar."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Uma versão mais recente do ${APPLICATION_NAME} já está instalada! Não é recomendada a instalação de uma versão mais antiga. Se realmente deseja instalar esta versão, aconselha-se a desinstalação da versão atual primeiro. Selecione a operação que deseja executar e clique em Avançar para continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} já está instalada.$\nSelecione a operação que deseja realizar e clique em 'Seguinte' para continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Adicionar/Reinstalar Componentes"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
@@ -20,17 +20,17 @@ StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "A instalar integração para Wi
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Atalho do progama no Menu Inicial"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "A adicionar o atalho de ${APPLICATION_NAME} ao Menu Inicial."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Atalho da área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "A criar atalhos na área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "A criar atalhos da área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atalho de início rápido"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "A criar atalho de início rápido"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "O essencial de ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Atalho de ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Atalho do ambiente de trabalho para ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Atalho no ambiente de trabalho de ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Atalho de início rápido de ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "A escrever o Desinstalador"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "A escrever chaves de registo do instalador"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Terminado"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Não parece que a aplicação ${APPLICATION_NAME} esteja instalada no diretório '$INSTDIR'.$\n$\nContinuar na mesma (não recomendado)?"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Não parece que ${APPLICATION_NAME} esteja instalado no diretório '$INSTDIR'.$\n$\nContinuar na mesma (não recomendado)?"
|
||||
StrCpy $UNINSTALL_ABORT "Desinstalação cancelada pelo utilizador"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Atalho de Início Rápido (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Atalho do Ambiente de Trabalho (sobrepõe o existente)"
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Neodin
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Už je nainštalovaný"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Vyberte si, ako chcete nainštalova� ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Novšia verzia ${APPLICATION_NAME} je už nainštalovaná! Neodporúèam vám nainštalova� staršiu verziu. Ak naozaj chcete nainštalova� túto staršiu verziu, je lepšie najprv odinštalova� aktuálnu verziu. Vyberte operáciu, ktorú chcete vykona�, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} je už nainštalovaná.$\n$\nVyberte operáciu, ktorú chcete vykona�, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Prida�/Preinštalova� komponenty"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Odinštalova� ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinštalova� ${APPLICATION_NAME}"
|
||||
@@ -38,6 +37,7 @@ StrCpy $UAC_ERROR_ELEVATE "Nemo
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Tento inštalátor vyžaduje admin prístup, skúste to znova"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "Inštalátor je už spustený."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Tento odinštalátor vyžaduje admin prístup, skúste to znova"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Prihlasovacia služba nebeží! Prerušuje sa."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Odinštalátor je už spustený."
|
||||
StrCpy $SectionGroup_Shortcuts "Zástupcovia"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar las notas de la versión"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "El/los proceso/s ${APPLICATION_EXECUTABLE} debe/n ser detenidos.$\n¿Quiere que el instalador lo haga por usted?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Deteniendo el/los proceso/s ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "¡Proceso para finalizar no encontrado!"
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "¡Proceso para detener no encontrado!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} se encuentra instalada en el sistema. Se recomienda de instalar la versión actual antes de instalar la nueva. Seleccione la operacion deseada y haga click en Siguiente para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "No desinstalar"
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Avinstallera inte"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Redan installerad"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Välj hur du vill installera ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "En nyare version av ${APPLICATION_NAME} är redan installerad! Det rekommenderas inte att du installerar en äldre version. Om du verkligen vill installera denna äldre versionen, är det bättre att du avinstallerar den nuvarande versionen först. Välj den åtgärd du vill utföra och klicka Nästa för att fortsätta."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} är redan installerad.$\n$\nVälj den åtgärd du vill utföra och klicka på Nästa för att fortsätta."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Lägg till/Ominstallera komponenter"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Avinstallera ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Avinstallera ${APPLICATION_NAME}"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver adm
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Login-service körs inte, avbryter!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan."
|
||||
StrCpy $SectionGroup_Shortcuts "Genvägar"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกที่มี"
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกประจำรุ่น"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "พบว่ากระบวนการ ${APPLICATION_EXECUTABLE} จะต้องหยุดทำงาน$\nคุณต้องการติดตั้งเพื่อหยุดการทำงานเหล่านี้ของคุณ?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "ฆ่ากระบวนการทำงาน ${APPLICATION_EXECUTABLE}"
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "ไม่พบการฆ่ากระบวนการ!"
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
!insertmacro MUI_LANGUAGE "Swedish"
|
||||
!insertmacro MUI_LANGUAGE "Estonian"
|
||||
!insertmacro MUI_LANGUAGE "Turkish"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Slovenian"
|
||||
!insertmacro MUI_LANGUAGE "SpanishInternational"
|
||||
!insertmacro MUI_LANGUAGE "Dutch"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Hungarian"
|
||||
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "Catalan"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Thai"
|
||||
!insertmacro MUI_LANGUAGE "Finnish"
|
||||
!insertmacro MUI_LANGUAGE "Basque"
|
||||
!insertmacro MUI_LANGUAGE "Greek"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Catalan"
|
||||
!insertmacro MUI_LANGUAGE "Italian"
|
||||
!insertmacro MUI_LANGUAGE "Portuguese"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Japanese"
|
||||
!insertmacro MUI_LANGUAGE "Galician"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "Slovak"
|
||||
!insertmacro MUI_LANGUAGE "Spanish"
|
||||
!insertmacro MUI_LANGUAGE "Polish"
|
||||
|
||||
@@ -22,18 +22,12 @@ if( Qt5Core_FOUND )
|
||||
find_package(Qt5Test REQUIRED)
|
||||
endif()
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
find_package(Qt5WebKitWidgets REQUIRED)
|
||||
find_package(Qt5WebKit REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
if(APPLE)
|
||||
find_package(Qt5MacExtras REQUIRED)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT NO_SHIBBOLETH)
|
||||
find_package(Qt5WebKitWidgets)
|
||||
find_package(Qt5WebKit)
|
||||
if(NOT Qt5WebKitWidgets_FOUND)
|
||||
message(FATAL_ERROR "Qt5WebKit required for Shibboleth. Use -DNO_SHIBBOLETH=1 to disable it.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else( Qt5Core_FOUND )
|
||||
|
||||
@@ -23,6 +23,4 @@
|
||||
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
||||
#cmakedefine SHAREDIR "@SHAREDIR@"
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,8 +41,6 @@ endif (MEM_NULL_TESTS)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
include(AddCMockaTest)
|
||||
|
||||
@@ -62,4 +62,8 @@ if (WIN32)
|
||||
check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF)
|
||||
endif(WIN32)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
set(CSYNC_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "csync required system libraries")
|
||||
|
||||
@@ -387,6 +387,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
trav.inode = cur->inode;
|
||||
|
||||
trav.error_status = cur->error_status;
|
||||
trav.should_update_metadata = cur->should_update_metadata;
|
||||
trav.has_ignored_files = cur->has_ignored_files;
|
||||
trav.checksum = cur->checksum;
|
||||
trav.checksumTypeId = cur->checksumTypeId;
|
||||
|
||||
+17
-17
@@ -98,7 +98,6 @@ enum csync_status_codes_e {
|
||||
CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK,
|
||||
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
|
||||
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
|
||||
CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE,
|
||||
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME,
|
||||
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
|
||||
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN,
|
||||
@@ -125,22 +124,20 @@ typedef enum csync_status_codes_e CSYNC_STATUS;
|
||||
* the csync state of a file.
|
||||
*/
|
||||
enum csync_instructions_e {
|
||||
CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */
|
||||
CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL_RENAME = 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */
|
||||
CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */
|
||||
CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
||||
CSYNC_INSTRUCTION_ERROR = 0x00000100,
|
||||
CSYNC_INSTRUCTION_TYPE_CHANGE = 0x00000200, /* Like NEW, but deletes the old entity first (RECONCILE)
|
||||
Used when the type of something changes from directory to file
|
||||
or back. */
|
||||
CSYNC_INSTRUCTION_UPDATE_METADATA = 0x00000400, /* If the etag has been updated and need to be writen to the db,
|
||||
but without any propagation (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */
|
||||
CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL_RENAME= 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */
|
||||
CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */
|
||||
CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
||||
CSYNC_INSTRUCTION_ERROR = 0x00000100,
|
||||
CSYNC_INSTRUCTION_TYPE_CHANGE = 0x0000200, /* Like NEW, but deletes the old entity first (RECONCILE)
|
||||
Used when the type of something changes from directory to file
|
||||
or back. */
|
||||
};
|
||||
|
||||
enum csync_ftw_type_e {
|
||||
@@ -256,6 +253,9 @@ struct csync_tree_walk_file_s {
|
||||
enum csync_ftw_type_e type;
|
||||
enum csync_instructions_e instruction;
|
||||
|
||||
/* For directories: If the etag has been updated and need to be writen on the db */
|
||||
int should_update_metadata;
|
||||
|
||||
/* For directories: Does it have children that were ignored (hidden or ignore pattern) */
|
||||
int has_ignored_files;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifndef WITH_UNIT_TESTING
|
||||
#ifndef NDEBUG
|
||||
static
|
||||
#endif
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||
@@ -243,14 +243,9 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
||||
// distinguish files ending in '.' from files without an ending,
|
||||
// as '.' is a separator that is not stored internally, so let's
|
||||
// not allow to sync those to avoid file loss/ambiguities (#416)
|
||||
if (blen > 1) {
|
||||
if (bname[blen-1]== ' ') {
|
||||
match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
|
||||
goto out;
|
||||
} else if (bname[blen-1]== '.' ) {
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
}
|
||||
if (blen > 1 && (bname[blen-1]== ' ' || bname[blen-1]== '.' )) {
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (csync_is_windows_reserved_word(bname)) {
|
||||
|
||||
@@ -27,14 +27,13 @@ enum csync_exclude_type_e {
|
||||
CSYNC_FILE_EXCLUDE_AND_REMOVE,
|
||||
CSYNC_FILE_EXCLUDE_LIST,
|
||||
CSYNC_FILE_EXCLUDE_INVALID_CHAR,
|
||||
CSYNC_FILE_EXCLUDE_TRAILING_SPACE,
|
||||
CSYNC_FILE_EXCLUDE_LONG_FILENAME,
|
||||
CSYNC_FILE_EXCLUDE_HIDDEN,
|
||||
CSYNC_FILE_EXCLUDE_STAT_FAILED
|
||||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef NDEBUG
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -186,6 +186,8 @@ struct csync_file_stat_s {
|
||||
mode_t mode; /* u32 */
|
||||
unsigned int type : 4;
|
||||
unsigned int child_modified : 1;
|
||||
unsigned int should_update_metadata : 1; /*specify that the etag, or the remote perm or fileid has
|
||||
changed and need to be updated on the db even for INSTRUCTION_NONE */
|
||||
unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */
|
||||
|
||||
char *destpath; /* for renames */
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "csync_private.h"
|
||||
#include "csync_reconcile.h"
|
||||
#include "csync_util.h"
|
||||
@@ -131,7 +130,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
break;
|
||||
/* file has been removed on the opposite replica */
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (cur->has_ignored_files) {
|
||||
/* Do not remove a directory that has ignored files */
|
||||
break;
|
||||
@@ -183,8 +181,13 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
|
||||
if(!other) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
if (cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
// For new directories we always want to update the etag once
|
||||
// the directory has been propagated. Otherwise the directory
|
||||
// could appear locally without being added to the database.
|
||||
cur->should_update_metadata = true;
|
||||
}
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_NONE
|
||||
|| other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
|| cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
other->destpath = c_strdup( cur->path );
|
||||
@@ -192,6 +195,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
other->should_update_metadata = true;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
@@ -201,12 +205,12 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
other->should_update_metadata = true;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
} else {
|
||||
assert(other->type != CSYNC_FTW_TYPE_DIR);
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
}
|
||||
@@ -218,19 +222,13 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bool is_conflict = true;
|
||||
bool is_equal_files = false;
|
||||
/*
|
||||
* file found on the other replica
|
||||
*/
|
||||
other = (csync_file_stat_t *) node->data;
|
||||
|
||||
switch (cur->instruction) {
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) {
|
||||
// Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last.
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_EVAL_RENAME:
|
||||
/* If the file already exist on the other side, we have a conflict.
|
||||
Abort the rename and consider it is a new file. */
|
||||
@@ -255,39 +253,42 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
if (other->type == CSYNC_FTW_TYPE_DIR &&
|
||||
cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
// Folders of the same path are always considered equals
|
||||
is_conflict = false;
|
||||
is_equal_files = (other->modtime == cur->modtime);
|
||||
} else {
|
||||
is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime));
|
||||
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
|
||||
// FIXME: do a binary comparision of the file here because of the following
|
||||
// edge case:
|
||||
// The files could still have different content, even though the mtime
|
||||
// and size are the same.
|
||||
}
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
// If the files are considered equal, only update the DB with the etag from remote
|
||||
cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
if (is_equal_files) {
|
||||
/* The files are considered equal. */
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
|
||||
/* update DB with new etag from remote */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
other->should_update_metadata = true;
|
||||
} else {
|
||||
cur->should_update_metadata = true;
|
||||
}
|
||||
} else if(ctx->current == REMOTE_REPLICA) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
}
|
||||
|
||||
break;
|
||||
/* file on the other replica has not been modified */
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (cur->type != other->type) {
|
||||
// If the type of the entity changed, it's like NEW, but
|
||||
// needs to delete the other entity first.
|
||||
cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
cur->instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_IGNORE:
|
||||
@@ -309,7 +310,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-30s %s dir: %s",
|
||||
"%-20s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -317,7 +318,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-30s %s file: %s",
|
||||
"%-20s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -328,7 +329,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-30s %s dir: %s",
|
||||
"%-20s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -336,7 +337,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-30s %s file: %s",
|
||||
"%-20s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
|
||||
+19
-18
@@ -314,7 +314,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
}
|
||||
if (checksumIdentical) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
|
||||
st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
st->should_update_metadata = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -340,19 +341,18 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
|
||||
ctx->remote.read_from_db = true;
|
||||
}
|
||||
if (metadata_differ) {
|
||||
/* file id or permissions has changed. Which means we need to update them in the DB. */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
|
||||
st->should_update_metadata = true;
|
||||
}
|
||||
/* If it was remembered in the db that the remote dir has ignored files, store
|
||||
* that so that the reconciler can make advantage of.
|
||||
*/
|
||||
if( ctx->current == REMOTE_REPLICA ) {
|
||||
st->has_ignored_files = tmp->has_ignored_files;
|
||||
}
|
||||
if (metadata_differ) {
|
||||
/* file id or permissions has changed. Which means we need to update them in the DB. */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
|
||||
st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
} else {
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
@@ -477,8 +477,6 @@ out:
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
|
||||
@@ -488,9 +486,7 @@ out:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st->instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& st->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& type != CSYNC_FTW_TYPE_DIR) {
|
||||
st->child_modified = 1;
|
||||
}
|
||||
@@ -879,11 +875,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
|
||||
if (ctx->current_fs && !ctx->current_fs->child_modified
|
||||
&& ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
} else {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
ctx->current_fs->should_update_metadata = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) {
|
||||
@@ -897,6 +892,12 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
previous_fs->child_modified = ctx->current_fs->child_modified;
|
||||
}
|
||||
|
||||
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
|
||||
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
|
||||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
|
||||
ctx->current_fs->should_update_metadata = true;
|
||||
}
|
||||
|
||||
ctx->current_fs = previous_fs;
|
||||
ctx->remote.read_from_db = read_from_db;
|
||||
SAFE_FREE(filename);
|
||||
|
||||
@@ -56,7 +56,6 @@ static const _instr_code_struct _instr[] =
|
||||
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
|
||||
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
|
||||
{ "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
|
||||
{ "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA },
|
||||
{ NULL, CSYNC_INSTRUCTION_ERROR }
|
||||
};
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
static void setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
|
||||
@@ -178,20 +179,6 @@ static void check_csync_excluded(void **state)
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "latex/songbook/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
#ifdef _WIN32
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_space ", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_dot.", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "AUX", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void check_csync_excluded_traversal(void **state)
|
||||
@@ -318,14 +305,13 @@ static void check_csync_excluded_performance(void **state)
|
||||
|
||||
const int N = 10000;
|
||||
int totalRc = 0;
|
||||
int i = 0;
|
||||
|
||||
// Being able to use QElapsedTimer for measurement would be nice...
|
||||
{
|
||||
struct timeval before, after;
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
totalRc += csync_excluded_no_ctx(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
|
||||
totalRc += csync_excluded_no_ctx(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
|
||||
}
|
||||
@@ -343,7 +329,7 @@ static void check_csync_excluded_performance(void **state)
|
||||
struct timeval before, after;
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
totalRc += csync_excluded_traversal(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
|
||||
totalRc += csync_excluded_traversal(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ static void teardown(void **state) {
|
||||
static void check_csync_init(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
csync_init(csync);
|
||||
|
||||
|
||||
@@ -520,7 +520,7 @@ sub put_to_dir( $$;$ )
|
||||
$targetUrl = $optionsRef->{url};
|
||||
}
|
||||
}
|
||||
$d->open($targetUrl . $dir);
|
||||
$d->open($dir);
|
||||
|
||||
my $filename = $file;
|
||||
$filename =~ s/^.*\///;
|
||||
|
||||
@@ -31,13 +31,6 @@ use strict;
|
||||
|
||||
print "Hello, this is t6, a tester for csync with ownCloud.\n";
|
||||
|
||||
# Checking CURL is installed to avoid misleading errors later...
|
||||
system(("curl", "--help", ">", "/dev/null"));
|
||||
if ($? != 0) {
|
||||
print "CURL is needed for this script, aborting with error\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
initTesting();
|
||||
|
||||
sub createPostUpdateScript($)
|
||||
|
||||
@@ -56,6 +56,8 @@ assertLocalAndRemoteDir( '', 0);
|
||||
printInfo( "Testing with a .sys.admin#recall#" );
|
||||
system("echo 'dir/file2.dat' > ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo 'dir/file3.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo 'nonexistant' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo '/tmp/t_recall/file4.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
glob_put( "$tmpdir/.sys.admin\#recall\#", "" );
|
||||
|
||||
csync();
|
||||
@@ -68,6 +70,10 @@ assert( -e glob(localDir().'dir/file3_.sys.admin#recall#-*.dat' ) );
|
||||
assert( -e glob(localDir().'dir/file2.dat' ) );
|
||||
assert( -e glob(localDir().'dir/file3.dat' ) );
|
||||
|
||||
assert( !-e glob(localDir().'nonexistant*' ) );
|
||||
assert( !-e glob('/tmp/t_recall/file4_.sys.admin#recall#-*.dat' ) );
|
||||
assert( -e glob('/tmp/t_recall/file4.dat' ) );
|
||||
|
||||
#Remove the recall file
|
||||
unlink(localDir() . ".sys.admin#recall#");
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ On Microsoft Windows systems:
|
||||
``%LOCALAPPDATA%\ownCloud\owncloud.cfg``
|
||||
|
||||
On MAC OS X systems:
|
||||
``$HOME/Library/Application Support/ownCloud/owncloud.cfg``
|
||||
``$HOME/Library/Application Support/ownCloud``
|
||||
|
||||
|
||||
The configuration file contains settings using the Microsoft Windows .ini file
|
||||
|
||||
+4
-12
@@ -1,11 +1,3 @@
|
||||
<!---
|
||||
Please try to only report a bug if it happens with the latest version
|
||||
The latest version can be seen by checking the ChangeLog: https://owncloud.org/changelog/desktop/
|
||||
|
||||
For support try: https://central.owncloud.org/c/help/desktop-file-sync
|
||||
--->
|
||||
|
||||
|
||||
### Expected behaviour
|
||||
Tell us what should happen
|
||||
|
||||
@@ -28,7 +20,7 @@ PHP version:
|
||||
|
||||
ownCloud version:
|
||||
|
||||
Storage backend (external storage):
|
||||
Storage backend:
|
||||
|
||||
### Client configuration
|
||||
Client version:
|
||||
@@ -46,11 +38,11 @@ logs.
|
||||
|
||||
```Template for output < 10 lines```
|
||||
|
||||
1. Client logfile: Output of `owncloud --logwindow` or `owncloud --logfile log.txt`
|
||||
1. Output of `owncloud --logwindow` or `owncloud --logfile log.txt`
|
||||
(On Windows using `cmd.exe`, you might need to first `cd` into the ownCloud directory)
|
||||
(See also http://doc.owncloud.org/desktop/2.2/troubleshooting.html#client-logfile )
|
||||
(See also http://doc.owncloud.org/desktop/1.8/troubleshooting.html#client-logfile )
|
||||
|
||||
2. Web server error log:
|
||||
|
||||
3. Server logfile: ownCloud log (data/owncloud.log):
|
||||
3. ownCloud log (data/owncloud.log):
|
||||
|
||||
|
||||
@@ -292,6 +292,66 @@ 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
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <qcoreevent.h>
|
||||
#include <QFile>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
#include "config.h"
|
||||
|
||||
OwncloudDolphinPluginHelper* OwncloudDolphinPluginHelper::instance()
|
||||
{
|
||||
@@ -67,7 +68,10 @@ void OwncloudDolphinPluginHelper::tryConnect()
|
||||
return;
|
||||
}
|
||||
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
||||
QString socketPath = runtimeDir + QLatin1String("/ownCloud/socket");
|
||||
runtimeDir.append( QChar('/'));
|
||||
runtimeDir.append( QLatin1String(APPLICATION_SHORTNAME) );
|
||||
|
||||
const QString socketPath = runtimeDir + QLatin1String("/socket");
|
||||
_socket.connectToServer(socketPath);
|
||||
}
|
||||
|
||||
|
||||
+1
-24
@@ -18,7 +18,6 @@
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <qdebug.h>
|
||||
|
||||
#include "account.h"
|
||||
@@ -29,7 +28,6 @@
|
||||
#include "syncengine.h"
|
||||
#include "syncjournaldb.h"
|
||||
#include "config.h"
|
||||
#include "connectionvalidator.h"
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
@@ -69,8 +67,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:
|
||||
@@ -200,12 +196,10 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
|
||||
if (!options->source_dir.endsWith('/')) {
|
||||
options->source_dir.append('/');
|
||||
}
|
||||
QFileInfo fi(options->source_dir);
|
||||
if( !fi.exists() ) {
|
||||
if( !QFile::exists( options->source_dir )) {
|
||||
std::cerr << "Source dir '" << qPrintable(options->source_dir) << "' does not exist." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
options->source_dir = fi.absoluteFilePath();
|
||||
|
||||
QStringListIterator it(args);
|
||||
// skip file name;
|
||||
@@ -391,23 +385,6 @@ int main(int argc, char **argv) {
|
||||
account->setCredentials(cred);
|
||||
account->setSslErrorHandler(sslErrorHandler);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
//obtain capabilities using event loop
|
||||
QEventLoop loop;
|
||||
|
||||
JsonApiJob *job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/capabilities"));
|
||||
job->setTimeout(timeoutToUseMsec);
|
||||
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QVariantMap &json) {
|
||||
auto caps = json.value("ocs").toMap().value("data").toMap().value("capabilities");
|
||||
qDebug() << "Server capabilities" << caps;
|
||||
account->setCapabilities(caps.toMap());
|
||||
loop.quit();
|
||||
});
|
||||
job->start();
|
||||
|
||||
loop.exec();
|
||||
#endif
|
||||
|
||||
// much lower age than the default since this utility is usually made to be run right after a change in the tests
|
||||
SyncEngine::minimumFileAgeForUpload = 0;
|
||||
|
||||
|
||||
@@ -94,26 +94,22 @@ set(client_SRCS
|
||||
servernotificationhandler.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
creds/httpcredentialsgui.cpp
|
||||
creds/shibbolethcredentials.cpp
|
||||
creds/shibboleth/shibbolethwebview.cpp
|
||||
creds/shibboleth/shibbolethuserjob.cpp
|
||||
wizard/postfixlineedit.cpp
|
||||
wizard/abstractcredswizardpage.cpp
|
||||
wizard/owncloudadvancedsetuppage.cpp
|
||||
wizard/owncloudconnectionmethoddialog.cpp
|
||||
wizard/owncloudhttpcredspage.cpp
|
||||
wizard/owncloudsetuppage.cpp
|
||||
wizard/owncloudshibbolethcredspage.cpp
|
||||
wizard/owncloudwizardcommon.cpp
|
||||
wizard/owncloudwizard.cpp
|
||||
wizard/owncloudwizardresultpage.cpp
|
||||
../3rdparty/qjson/json.cpp
|
||||
)
|
||||
|
||||
IF(NOT NO_SHIBBOLETH)
|
||||
list(APPEND client_SRCS
|
||||
creds/shibbolethcredentials.cpp
|
||||
creds/shibboleth/shibbolethwebview.cpp
|
||||
creds/shibboleth/shibbolethuserjob.cpp
|
||||
wizard/owncloudshibbolethcredspage.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(updater_SRCS
|
||||
updater/ocupdater.cpp
|
||||
@@ -236,9 +232,6 @@ set(ownCloud ${ownCloud_old})
|
||||
if (WITH_DBUS)
|
||||
set(ADDITIONAL_APP_MODULES DBus)
|
||||
endif(WITH_DBUS)
|
||||
if (NOT NO_SHIBBOLETH)
|
||||
list(APPEND ADDITIONAL_APP_MODULES WebKitWidgets)
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||
|
||||
@@ -257,14 +250,14 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||
|
||||
# add_executable( ${APPLICATION_EXECUTABLE} main.cpp ${final_src})
|
||||
add_executable( ${APPLICATION_EXECUTABLE} WIN32 main.cpp ${final_src})
|
||||
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml Sql ${ADDITIONAL_APP_MODULES})
|
||||
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml WebKitWidgets Sql ${ADDITIONAL_APP_MODULES})
|
||||
else()
|
||||
# set(CMAKE_INSTALL_PREFIX ".") # Examples use /Applications. hurmpf.
|
||||
set(MACOSX_BUNDLE_ICON_FILE "ownCloud.icns")
|
||||
|
||||
# we must add MACOSX_BUNDLE only if building a bundle
|
||||
add_executable( ${APPLICATION_EXECUTABLE} WIN32 MACOSX_BUNDLE main.cpp ${final_src})
|
||||
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml Sql ${ADDITIONAL_APP_MODULES})
|
||||
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml WebKitWidgets Sql ${ADDITIONAL_APP_MODULES})
|
||||
|
||||
set (QM_DIR ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/Translations)
|
||||
install(FILES ${client_I18N} DESTINATION ${QM_DIR})
|
||||
|
||||
@@ -248,9 +248,6 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
QHash<QString, int> accNotified;
|
||||
QString listAccountName;
|
||||
|
||||
// Whether a new notification widget was added to the notificationLayout.
|
||||
bool newNotificationShown = false;
|
||||
|
||||
foreach( auto activity, list ) {
|
||||
if( _blacklistedNotifications.contains(activity)) {
|
||||
qDebug() << Q_FUNC_INFO << "Activity in blacklist, skip";
|
||||
@@ -274,7 +271,6 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
_ui->_notifyScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
|
||||
#endif
|
||||
_widgetForNotifId[activity.ident()] = widget;
|
||||
newNotificationShown = true;
|
||||
}
|
||||
|
||||
widget->setActivity( activity );
|
||||
@@ -369,10 +365,6 @@ void ActivityWidget::slotBuildNotificationDisplay(const ActivityList& list)
|
||||
const QString log = tr("%1 Notifications - Action Required").arg(Theme::instance()->appNameGUI());
|
||||
emit guiLog( log, msg);
|
||||
}
|
||||
|
||||
if (newNotificationShown) {
|
||||
emit newNotification();
|
||||
}
|
||||
}
|
||||
|
||||
void ActivityWidget::slotSendNotificationRequest(const QString& accountName, const QString& link, const QByteArray& verb)
|
||||
@@ -525,7 +517,6 @@ ActivitySettings::ActivitySettings(QWidget *parent)
|
||||
connect(_activityWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
|
||||
connect(_activityWidget, SIGNAL(hideActivityTab(bool)), this, SLOT(setActivityTabHidden(bool)));
|
||||
connect(_activityWidget, SIGNAL(guiLog(QString,QString)), this, SIGNAL(guiLog(QString,QString)));
|
||||
connect(_activityWidget, SIGNAL(newNotification()), SLOT(slotShowActivityTab()));
|
||||
|
||||
_protocolWidget = new ProtocolWidget(this);
|
||||
_tab->insertTab(1, _protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
|
||||
@@ -591,13 +582,6 @@ void ActivitySettings::slotShowIssueItemCount(int cnt)
|
||||
_tab->setTabText(_syncIssueTabId, cntText);
|
||||
}
|
||||
|
||||
void ActivitySettings::slotShowActivityTab()
|
||||
{
|
||||
if (_activityTabId != -1) {
|
||||
_tab->setCurrentIndex(_activityTabId);
|
||||
}
|
||||
}
|
||||
|
||||
void ActivitySettings::slotCopyToClipboard()
|
||||
{
|
||||
QString text;
|
||||
|
||||
@@ -81,7 +81,7 @@ signals:
|
||||
void copyToClipboard();
|
||||
void rowsInserted();
|
||||
void hideActivityTab(bool);
|
||||
void newNotification();
|
||||
void newNotificationList(const ActivityList& list);
|
||||
|
||||
private slots:
|
||||
void slotBuildNotificationDisplay(const ActivityList& list);
|
||||
@@ -143,7 +143,6 @@ private slots:
|
||||
void setActivityTabHidden(bool hidden);
|
||||
void slotRegularNotificationCheck();
|
||||
void slotShowIssueItemCount(int cnt);
|
||||
void slotShowActivityTab();
|
||||
|
||||
signals:
|
||||
void guiLog(const QString&, const QString&);
|
||||
|
||||
@@ -360,11 +360,10 @@ void Application::setupLogging()
|
||||
|
||||
Logger::instance()->enterNextLogFile();
|
||||
|
||||
qDebug() << QString::fromLatin1( "################## %1 %2 (%3) %4 on %5").arg(_theme->appName())
|
||||
qDebug() << QString::fromLatin1( "################## %1 %2 (%3) %4").arg(_theme->appName())
|
||||
.arg( QLocale::system().name() )
|
||||
.arg(property("ui_lang").toString())
|
||||
.arg(_theme->version())
|
||||
.arg(Utility::platformName());
|
||||
.arg(_theme->version());
|
||||
|
||||
// Setup CSYNC logging to forward to our own logger
|
||||
csync_set_log_callback( csyncLogCatcher );
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
#include "creds/credentialsfactory.h"
|
||||
#include "creds/httpcredentialsgui.h"
|
||||
#include "creds/dummycredentials.h"
|
||||
#ifndef NO_SHIBBOLETH
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#endif
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
@@ -33,10 +31,8 @@ AbstractCredentials* create(const QString& type)
|
||||
return new HttpCredentialsGui;
|
||||
} else if (type == "dummy") {
|
||||
return new DummyCredentials;
|
||||
#ifndef NO_SHIBBOLETH
|
||||
} else if (type == "shibboleth") {
|
||||
return new ShibbolethCredentials;
|
||||
#endif
|
||||
} else {
|
||||
qWarning("Unknown credentials type: %s", qPrintable(type));
|
||||
return new DummyCredentials;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include "creds/httpcredentialsgui.h"
|
||||
#include "theme.h"
|
||||
#include "account.h"
|
||||
@@ -32,52 +31,26 @@ void HttpCredentialsGui::askFromUser()
|
||||
|
||||
void HttpCredentialsGui::askFromUserAsync()
|
||||
{
|
||||
QString msg = tr("Please enter %1 password:<br>"
|
||||
"<br>"
|
||||
"User: %2<br>"
|
||||
"Account: %3<br>")
|
||||
.arg(Utility::escape(Theme::instance()->appNameGUI()),
|
||||
Utility::escape(_user),
|
||||
Utility::escape(_account->displayName()));
|
||||
|
||||
QString reqTxt = requestAppPasswordText(_account);
|
||||
if (!reqTxt.isEmpty()) {
|
||||
msg += QLatin1String("<br>") + reqTxt + QLatin1String("<br>");
|
||||
}
|
||||
QString msg = tr("Please enter %1 password:\n"
|
||||
"\n"
|
||||
"User: %2\n"
|
||||
"Account: %3\n")
|
||||
.arg(Theme::instance()->appNameGUI(), _user, _account->displayName());
|
||||
if (!_fetchErrorString.isEmpty()) {
|
||||
msg += QLatin1String("<br>") + tr("Reading from keychain failed with error: '%1'").arg(
|
||||
Utility::escape(_fetchErrorString)) + QLatin1String("<br>");
|
||||
msg += QLatin1String("\n") + tr("Reading from keychain failed with error: '%1'").arg(
|
||||
_fetchErrorString) + QLatin1String("\n");
|
||||
}
|
||||
|
||||
QInputDialog dialog;
|
||||
dialog.setWindowTitle(tr("Enter Password"));
|
||||
dialog.setLabelText(msg);
|
||||
dialog.setTextValue(_previousPassword);
|
||||
dialog.setTextEchoMode(QLineEdit::Password);
|
||||
if (QLabel *dialogLabel = dialog.findChild<QLabel *>()) {
|
||||
dialogLabel->setOpenExternalLinks(true);
|
||||
dialogLabel->setTextFormat(Qt::RichText);
|
||||
}
|
||||
|
||||
bool ok = dialog.exec();
|
||||
bool ok = false;
|
||||
QString pwd = QInputDialog::getText(0, tr("Enter Password"), msg,
|
||||
QLineEdit::Password, _previousPassword,
|
||||
&ok);
|
||||
if (ok) {
|
||||
_password = dialog.textValue();
|
||||
_password = pwd;
|
||||
_ready = true;
|
||||
persist();
|
||||
}
|
||||
emit asked();
|
||||
}
|
||||
|
||||
QString HttpCredentialsGui::requestAppPasswordText(const Account* account)
|
||||
{
|
||||
if (account->serverVersionInt() < 0x090100) {
|
||||
// Older server than 9.1 does not have trhe feature to request App Password
|
||||
return QString();
|
||||
}
|
||||
|
||||
return tr("<a href=\"%1\">Click here</a> to request an app password from the web interface.")
|
||||
.arg(account->url().toString() + QLatin1String("/index.php/settings/personal?section=apppasswords"));
|
||||
}
|
||||
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -30,8 +30,6 @@ public:
|
||||
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
||||
void askFromUser() Q_DECL_OVERRIDE;
|
||||
Q_INVOKABLE void askFromUserAsync();
|
||||
|
||||
static QString requestAppPasswordText(const Account *account);
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
+15
-17
@@ -62,7 +62,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
, _consecutiveFailingSyncs(0)
|
||||
, _consecutiveFollowUpSyncs(0)
|
||||
, _journal(definition.localPath)
|
||||
, _fileLog(new SyncRunFileLog)
|
||||
{
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
@@ -110,8 +109,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString)), this, SLOT(slotNewBigFolderDiscovered(QString)));
|
||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
SLOT(slotLogPropagationStart()));
|
||||
}
|
||||
|
||||
Folder::~Folder()
|
||||
@@ -367,11 +364,18 @@ void Folder::bubbleUpSyncResult()
|
||||
SyncFileItemPtr firstConflictItem;
|
||||
SyncFileItemPtr firstItemError;
|
||||
|
||||
SyncRunFileLog syncFileLog;
|
||||
|
||||
syncFileLog.start(path(), _engine->isSyncRunning() ? _engine->stopWatch() : Utility::StopWatch() );
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
foreach (const SyncFileItemPtr &item, _syncResult.syncFileItemVector() ) {
|
||||
// Process the item to the gui
|
||||
// Log the item
|
||||
syncFileLog.logItem( *item );
|
||||
|
||||
// and process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
slotSyncError( tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
@@ -410,9 +414,11 @@ void Folder::bubbleUpSyncResult()
|
||||
firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
updatedItems++;
|
||||
if (!firstItemUpdated)
|
||||
firstItemUpdated = item;
|
||||
if (!item->_isDirectory) {
|
||||
updatedItems++;
|
||||
if (!firstItemUpdated)
|
||||
firstItemUpdated = item;
|
||||
}
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||
@@ -434,6 +440,7 @@ void Folder::bubbleUpSyncResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
syncFileLog.close();
|
||||
|
||||
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
|
||||
_syncResult.setWarnCount(ignoredItems);
|
||||
@@ -751,8 +758,6 @@ void Folder::startSync(const QStringList &pathList)
|
||||
|
||||
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||
|
||||
// disable events until syncing is done
|
||||
@@ -816,7 +821,6 @@ void Folder::slotSyncFinished(bool success)
|
||||
} else {
|
||||
qDebug() << "-> SyncEngine finished without problem.";
|
||||
}
|
||||
_fileLog->finish();
|
||||
bubbleUpSyncResult();
|
||||
|
||||
bool anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
@@ -923,7 +927,6 @@ void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& jo
|
||||
// Count all error conditions.
|
||||
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||
}
|
||||
_fileLog->logItem(item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item, job);
|
||||
}
|
||||
|
||||
@@ -961,11 +964,6 @@ void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
||||
}
|
||||
}
|
||||
|
||||
void Folder::slotLogPropagationStart()
|
||||
{
|
||||
_fileLog->logLap("Propagation starts");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||
@@ -1000,7 +998,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||
void Folder::slotAboutToRestoreBackup(bool *restore)
|
||||
{
|
||||
QString msg =
|
||||
tr("This sync would reset the files to an earlier time in the sync folder '%1'.\n"
|
||||
tr("This sync would reset the files to an erlier time in the sync folder '%1'.\n"
|
||||
"This might be because a backup was restored on the server.\n"
|
||||
"Continuing the sync as normal will cause all your files to be overwritten by an older "
|
||||
"file in an earlier state. "
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace OCC {
|
||||
|
||||
class SyncEngine;
|
||||
class AccountState;
|
||||
class SyncRunFileLog;
|
||||
|
||||
/**
|
||||
* @brief The FolderDefinition class
|
||||
@@ -264,8 +263,6 @@ private slots:
|
||||
|
||||
void slotNewBigFolderDiscovered(const QString &);
|
||||
|
||||
void slotLogPropagationStart();
|
||||
|
||||
private:
|
||||
bool setIgnoredFiles();
|
||||
|
||||
@@ -314,8 +311,6 @@ private:
|
||||
SyncJournalDb _journal;
|
||||
|
||||
ClientProxy _clientProxy;
|
||||
|
||||
QScopedPointer<SyncRunFileLog> _fileLog;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -590,7 +590,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
QStringList sortedSubfolders = list;
|
||||
// skip the parent item (first in the list)
|
||||
sortedSubfolders.erase(sortedSubfolders.begin());
|
||||
Utility::sortFilenames(sortedSubfolders);
|
||||
sortedSubfolders.sort();
|
||||
|
||||
QVarLengthArray<int, 10> undecidedIndexes;
|
||||
|
||||
@@ -943,20 +943,11 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
|
||||
if (totalSize > 0) {
|
||||
QString s1 = Utility::octetsToString( completedSize );
|
||||
QString s2 = Utility::octetsToString( totalSize );
|
||||
|
||||
if (progress.trustEta()) {
|
||||
//: Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"
|
||||
overallSyncString = tr("%5 left, %1 of %2, file %3 of %4")
|
||||
.arg(s1, s2)
|
||||
.arg(currentFile).arg(totalFileCount)
|
||||
.arg( Utility::durationToDescriptiveString1(progress.totalProgress().estimatedEta) );
|
||||
|
||||
} else {
|
||||
//: Example text: "12 MB of 345 MB, file 6 of 7"
|
||||
overallSyncString = tr("%1 of %2, file %3 of %4")
|
||||
.arg(s1, s2)
|
||||
.arg(currentFile).arg(totalFileCount);
|
||||
}
|
||||
//: Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"
|
||||
overallSyncString = tr("%5 left, %1 of %2, file %3 of %4")
|
||||
.arg(s1, s2)
|
||||
.arg(currentFile).arg(totalFileCount)
|
||||
.arg( Utility::durationToDescriptiveString1(progress.totalProgress().estimatedEta) );
|
||||
} else if (totalFileCount > 0) {
|
||||
// Don't attempt to estimate the time left if there is no kb to transfer.
|
||||
overallSyncString = tr("file %1 of %2") .arg(currentFile).arg(totalFileCount);
|
||||
@@ -1076,14 +1067,11 @@ void FolderStatusModel::slotShowFetchProgress()
|
||||
auto idx = it.key();
|
||||
auto* info = infoForIndex(idx);
|
||||
if (info && info->_fetching) {
|
||||
bool add = !info->hasLabel();
|
||||
if (add) {
|
||||
if (!info->hasLabel()) {
|
||||
beginInsertRows(idx, 0, 0);
|
||||
}
|
||||
info->_fetchingLabel = true;
|
||||
if (add) {
|
||||
endInsertRows();
|
||||
}
|
||||
info->_fetchingLabel = true;
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list)
|
||||
root->setData(0, Qt::UserRole, "/");
|
||||
}
|
||||
QStringList sortedList = list;
|
||||
Utility::sortFilenames(sortedList);
|
||||
sortedList.sort();
|
||||
foreach (QString path, sortedList) {
|
||||
path.remove(webdavFolder);
|
||||
QStringList paths = path.split('/');
|
||||
|
||||
+15
-41
@@ -92,9 +92,9 @@ ownCloudGui::ownCloudGui(Application *parent) :
|
||||
this,SLOT(slotSyncStateChange(Folder*)));
|
||||
|
||||
connect( AccountManager::instance(), SIGNAL(accountAdded(AccountState*)),
|
||||
SLOT(setupContextMenuIfVisible()));
|
||||
SLOT(setupContextMenu()));
|
||||
connect( AccountManager::instance(), SIGNAL(accountRemoved(AccountState*)),
|
||||
SLOT(setupContextMenuIfVisible()));
|
||||
SLOT(setupContextMenu()));
|
||||
|
||||
connect( Logger::instance(), SIGNAL(guiLog(QString,QString)),
|
||||
SLOT(slotShowTrayMessage(QString,QString)));
|
||||
@@ -193,7 +193,7 @@ void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
||||
void ownCloudGui::slotSyncStateChange( Folder* folder )
|
||||
{
|
||||
slotComputeOverallSyncStatus();
|
||||
setupContextMenuIfVisible();
|
||||
setupContextMenu();
|
||||
|
||||
if( !folder ) {
|
||||
return; // Valid, just a general GUI redraw was needed.
|
||||
@@ -215,7 +215,7 @@ void ownCloudGui::slotSyncStateChange( Folder* folder )
|
||||
void ownCloudGui::slotFoldersChanged()
|
||||
{
|
||||
slotComputeOverallSyncStatus();
|
||||
setupContextMenuIfVisible();
|
||||
setupContextMenu();
|
||||
}
|
||||
|
||||
void ownCloudGui::slotOpenPath(const QString &path)
|
||||
@@ -225,7 +225,7 @@ void ownCloudGui::slotOpenPath(const QString &path)
|
||||
|
||||
void ownCloudGui::slotAccountStateChanged()
|
||||
{
|
||||
setupContextMenuIfVisible();
|
||||
setupContextMenu();
|
||||
slotComputeOverallSyncStatus();
|
||||
}
|
||||
|
||||
@@ -450,13 +450,9 @@ void ownCloudGui::setupContextMenu()
|
||||
_tray->hide();
|
||||
}
|
||||
_contextMenu->clear();
|
||||
slotRebuildRecentMenus();
|
||||
} else {
|
||||
_contextMenu.reset(new QMenu());
|
||||
|
||||
// Update the context menu whenever we're about to show it
|
||||
// to the user.
|
||||
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(setupContextMenu()));
|
||||
|
||||
_recentActionsMenu = new QMenu(tr("Recent Changes"), _contextMenu.data());
|
||||
// this must be called only once after creating the context menu, or
|
||||
// it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04).
|
||||
@@ -481,8 +477,6 @@ void ownCloudGui::setupContextMenu()
|
||||
#endif
|
||||
}
|
||||
_contextMenu->setTitle(Theme::instance()->appNameGUI() );
|
||||
slotRebuildRecentMenus();
|
||||
|
||||
// We must call deleteLater because we might be called from the press in one of the actions.
|
||||
foreach (auto menu, _accountMenus) { menu->deleteLater(); }
|
||||
_accountMenus.clear();
|
||||
@@ -558,11 +552,6 @@ void ownCloudGui::setupContextMenu()
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::setupContextMenuIfVisible()
|
||||
{
|
||||
if (_contextMenu && _contextMenu->isVisible())
|
||||
setupContextMenu();
|
||||
}
|
||||
|
||||
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)
|
||||
{
|
||||
@@ -669,29 +658,18 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo&
|
||||
} else if (progress.totalSize() == 0 ) {
|
||||
quint64 currentFile = progress.currentFile();
|
||||
quint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
|
||||
QString msg;
|
||||
if (progress.trustEta()) {
|
||||
msg = tr("Syncing %1 of %2 (%3 left)")
|
||||
.arg( currentFile ).arg( totalFileCount )
|
||||
.arg( Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta) );
|
||||
} else {
|
||||
msg = tr("Syncing %1 of %2")
|
||||
.arg( currentFile ).arg( totalFileCount );
|
||||
}
|
||||
_actionStatus->setText( msg );
|
||||
_actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
|
||||
.arg( currentFile ).arg( totalFileCount )
|
||||
.arg( Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta) ) );
|
||||
} else {
|
||||
QString totalSizeStr = Utility::octetsToString( progress.totalSize() );
|
||||
QString msg;
|
||||
if (progress.trustEta()) {
|
||||
msg = tr("Syncing %1 (%2 left)")
|
||||
.arg( totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta) );
|
||||
} else {
|
||||
msg = tr("Syncing %1")
|
||||
.arg( totalSizeStr );
|
||||
}
|
||||
_actionStatus->setText( msg );
|
||||
_actionStatus->setText( tr("Syncing %1 (%2 left)")
|
||||
.arg( totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
_actionRecent->setIcon( QIcon() ); // Fixme: Set a "in-progress"-item eventually.
|
||||
|
||||
if (!progress._lastCompletedItem.isEmpty()
|
||||
@@ -722,11 +700,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo&
|
||||
}
|
||||
_recentItemsActions.append(action);
|
||||
|
||||
// Update the "Recent" menu if the context menu is being shown,
|
||||
// otherwise it'll be updated later, when the context menu is opened.
|
||||
if (_contextMenu && _contextMenu->isVisible()) {
|
||||
slotRebuildRecentMenus();
|
||||
}
|
||||
slotRebuildRecentMenus();
|
||||
}
|
||||
|
||||
if (progress.isUpdatingEstimates()
|
||||
|
||||
@@ -57,7 +57,6 @@ signals:
|
||||
|
||||
public slots:
|
||||
void setupContextMenu();
|
||||
void setupContextMenuIfVisible();
|
||||
void slotComputeOverallSyncStatus();
|
||||
void slotShowTrayMessage(const QString &title, const QString &msg);
|
||||
void slotShowOptionalTrayMessage(const QString &title, const QString &msg);
|
||||
|
||||
@@ -142,15 +142,11 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
|
||||
|
||||
void OwncloudSetupWizard::slotOwnCloudFoundAuth(const QUrl& url, const QVariantMap &info)
|
||||
{
|
||||
auto serverVersion = CheckServerJob::version(info);
|
||||
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>")
|
||||
.arg(url.toString())
|
||||
.arg(Theme::instance()->appNameGUI())
|
||||
.arg(CheckServerJob::versionString(info))
|
||||
.arg(serverVersion));
|
||||
|
||||
_ocWizard->account()->setServerVersion(serverVersion);
|
||||
.arg(CheckServerJob::version(info)));
|
||||
|
||||
QString p = url.path();
|
||||
if (p.endsWith("/status.php")) {
|
||||
@@ -508,10 +504,6 @@ DetermineAuthTypeJob::DetermineAuthTypeJob(AccountPtr account, QObject *parent)
|
||||
: AbstractNetworkJob(account, QString(), parent)
|
||||
, _redirects(0)
|
||||
{
|
||||
// This job implements special redirect handling to detect redirections
|
||||
// to pages that are indicative of Shibboleth-using servers. Hence we
|
||||
// disable the standard job redirection handling here.
|
||||
_followRedirects = false;
|
||||
}
|
||||
|
||||
void DetermineAuthTypeJob::start()
|
||||
@@ -539,15 +531,12 @@ bool DetermineAuthTypeJob::finished()
|
||||
setupConnections(reply());
|
||||
return false; // don't discard
|
||||
} else {
|
||||
#ifndef NO_SHIBBOLETH
|
||||
QRegExp shibbolethyWords("SAML|wayf");
|
||||
|
||||
shibbolethyWords.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
if (redirection.toString().contains(shibbolethyWords)) {
|
||||
emit authType(WizardCommon::Shibboleth);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
// TODO: Send an error.
|
||||
// eh?
|
||||
emit authType(WizardCommon::HttpCreds);
|
||||
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
OwncloudWizard* _ocWizard;
|
||||
QString _initLocalFolder;
|
||||
QString _remoteFolder;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
}
|
||||
}
|
||||
|
||||
Utility::sortFilenames(list);
|
||||
list.sort();
|
||||
foreach (QString path, list) {
|
||||
auto size = job ? job->_sizes.value(path) : 0;
|
||||
path.remove(pathToRemove);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <QBuffer>
|
||||
#include <QClipboard>
|
||||
#include <QFileInfo>
|
||||
#include <QDesktopServices>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -54,10 +53,6 @@ ShareLinkWidget::ShareLinkWidget(AccountPtr account,
|
||||
_ui->pushButton_copy->setEnabled(false);
|
||||
connect(_ui->pushButton_copy, SIGNAL(clicked(bool)), SLOT(slotPushButtonCopyLinkPressed()));
|
||||
|
||||
_ui->pushButton_mail->setIcon(QIcon::fromTheme("mail-send"));
|
||||
_ui->pushButton_mail->setEnabled(false);
|
||||
connect(_ui->pushButton_mail, SIGNAL(clicked(bool)), SLOT(slotPushButtonMailLinkPressed()));
|
||||
|
||||
// the following progress indicator widgets are added to layouts which makes them
|
||||
// automatically deleted once the dialog dies.
|
||||
_pi_link = new QProgressIndicator();
|
||||
@@ -229,7 +224,6 @@ void ShareLinkWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shar
|
||||
if (share->getShareType() == Share::TypeLink) {
|
||||
_share = qSharedPointerDynamicCast<LinkShare>(share);
|
||||
_ui->pushButton_copy->show();
|
||||
_ui->pushButton_mail->show();
|
||||
|
||||
_ui->widget_shareLink->show();
|
||||
_ui->checkBox_shareLink->setChecked(true);
|
||||
@@ -274,7 +268,6 @@ void ShareLinkWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shar
|
||||
}
|
||||
|
||||
setShareLink(_share->getLink().toString());
|
||||
_ui->pushButton_mail->setEnabled(true);
|
||||
_ui->pushButton_copy->setEnabled(true);
|
||||
|
||||
// Connect all shares signals to gui slots
|
||||
@@ -331,7 +324,6 @@ void ShareLinkWidget::setShareLink( const QString& url )
|
||||
if( realUrl.isValid() ) {
|
||||
_shareUrl = url;
|
||||
_ui->pushButton_copy->setEnabled(true);
|
||||
_ui->pushButton_mail->setEnabled(true);
|
||||
} else {
|
||||
_shareUrl.clear();
|
||||
_ui->_labelShareLink->setText(QString::null);
|
||||
@@ -347,7 +339,6 @@ void ShareLinkWidget::slotDeleteShareFetched()
|
||||
_ui->lineEdit_password->clear();
|
||||
_ui->_labelShareLink->clear();
|
||||
_ui->pushButton_copy->setEnabled(false);
|
||||
_ui->pushButton_mail->setEnabled(false);
|
||||
_ui->widget_shareLink->hide();
|
||||
_ui->lineEdit_password->hide();
|
||||
_ui->pushButton_setPassword->setEnabled(false);
|
||||
@@ -378,7 +369,6 @@ void ShareLinkWidget::slotCheckBoxShareLinkClicked()
|
||||
_ui->lineEdit_password->setEnabled(true);
|
||||
_ui->lineEdit_password->setFocus();
|
||||
_ui->pushButton_copy->hide();
|
||||
_ui->pushButton_mail->hide();
|
||||
_ui->widget_shareLink->show();
|
||||
|
||||
slotCheckBoxPasswordClicked();
|
||||
@@ -424,7 +414,6 @@ void ShareLinkWidget::slotCreateShareRequiresPassword(const QString& message)
|
||||
_ui->lineEdit_password->setEnabled(true);
|
||||
_ui->lineEdit_password->setFocus();
|
||||
_ui->pushButton_copy->hide();
|
||||
_ui->pushButton_mail->hide();
|
||||
_ui->widget_shareLink->show();
|
||||
_ui->checkBox_expire->setEnabled(false);
|
||||
_ui->checkBox_editing->setEnabled(false);
|
||||
@@ -486,19 +475,6 @@ void ShareLinkWidget::slotPushButtonCopyLinkPressed()
|
||||
#endif
|
||||
}
|
||||
|
||||
void ShareLinkWidget::slotPushButtonMailLinkPressed()
|
||||
{
|
||||
QString fileName = _sharePath.mid(_sharePath.lastIndexOf('/') + 1);
|
||||
|
||||
QDesktopServices::openUrl(QUrl(QString(
|
||||
"mailto: "
|
||||
"?subject=I shared %1 with you"
|
||||
"&body=%2").arg(
|
||||
fileName,
|
||||
_shareUrl),
|
||||
QUrl::TolerantMode));
|
||||
}
|
||||
|
||||
void ShareLinkWidget::slotCheckBoxEditingClicked()
|
||||
{
|
||||
ShareLinkWidget::setPublicUpload(_ui->checkBox_editing->checkState() == Qt::Checked);
|
||||
|
||||
@@ -68,7 +68,6 @@ private slots:
|
||||
void slotPasswordReturnPressed();
|
||||
void slotPasswordChanged(const QString& newText);
|
||||
void slotPushButtonCopyLinkPressed();
|
||||
void slotPushButtonMailLinkPressed();
|
||||
void slotCheckBoxEditingClicked();
|
||||
void slotPublicUploadSet();
|
||||
|
||||
|
||||
@@ -195,13 +195,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_mail">
|
||||
<property name="text">
|
||||
<string>&Mail link</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_copy">
|
||||
<property name="text">
|
||||
|
||||
@@ -171,9 +171,7 @@ void SocketApi::slotReadSocket()
|
||||
Q_ASSERT(socket);
|
||||
|
||||
while(socket->canReadLine()) {
|
||||
// Make sure to normalize the input from the socket to
|
||||
// make sure that the path will match, especially on OS X.
|
||||
QString line = QString::fromUtf8(socket->readLine()).normalized(QString::NormalizationForm_C);
|
||||
QString line = QString::fromUtf8(socket->readLine());
|
||||
line.chop(1); // remove the '\n'
|
||||
QString command = line.split(":").value(0);
|
||||
QString function = QString(QLatin1String("command_")).append(command);
|
||||
|
||||
@@ -81,16 +81,13 @@ QString SyncRunFileLog::instructionToStr( csync_instructions_e inst )
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
re = "INST_TYPE_CHANGE";
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
re = "INST_METADATA";
|
||||
break;
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
void SyncRunFileLog::start(const QString &folderPath)
|
||||
void SyncRunFileLog::start(const QString &folderPath, const Utility::StopWatch &stopWatch )
|
||||
{
|
||||
const qint64 logfileMaxSize = 1024*1024; // 1MiB
|
||||
|
||||
@@ -111,6 +108,8 @@ void SyncRunFileLog::start(const QString &folderPath)
|
||||
_file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
|
||||
_out.setDevice( _file.data() );
|
||||
|
||||
QDateTime dt = stopWatch.startTime();
|
||||
QDateTime de = stopWatch.timeOfLap(QLatin1String("Sync Finished"));
|
||||
|
||||
if (!exists) {
|
||||
// We are creating a new file, add the note.
|
||||
@@ -123,9 +122,8 @@ void SyncRunFileLog::start(const QString &folderPath)
|
||||
}
|
||||
|
||||
|
||||
_totalDuration.start();
|
||||
_lapDuration.start();
|
||||
_out << "#=#=#=# Syncrun started " << dateTimeStr(QDateTime::currentDateTime()) << endl;
|
||||
_out << "#=#=#=# Syncrun started " << dateTimeStr(dt) << " until " << dateTimeStr(de) << " ("
|
||||
<< stopWatch.durationOfLap(QLatin1String("Sync Finished")) << " msec)" << endl;
|
||||
}
|
||||
|
||||
void SyncRunFileLog::logItem( const SyncFileItem& item )
|
||||
@@ -145,11 +143,7 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
||||
const QChar L = QLatin1Char('|');
|
||||
_out << ts << L;
|
||||
_out << QString::number(item._requestDuration) << L;
|
||||
if( item.log._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << item._file << L;
|
||||
} else {
|
||||
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
||||
}
|
||||
_out << item._file << L;
|
||||
_out << instructionToStr( item.log._instruction ) << L;
|
||||
_out << directionToStr( item._direction ) << L;
|
||||
_out << QString::number(item.log._modtime) << L;
|
||||
@@ -168,18 +162,8 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
||||
_out << endl;
|
||||
}
|
||||
|
||||
void SyncRunFileLog::logLap(const QString& name)
|
||||
void SyncRunFileLog::close()
|
||||
{
|
||||
_out << "#=#=#=#=# " << name << " " << dateTimeStr(QDateTime::currentDateTime())
|
||||
<< " (last step: " << _lapDuration.restart() << " msec"
|
||||
<< ", total: " << _totalDuration.elapsed() << " msec)" << endl;
|
||||
}
|
||||
|
||||
void SyncRunFileLog::finish()
|
||||
{
|
||||
_out << "#=#=#=# Syncrun finished " << dateTimeStr(QDateTime::currentDateTime())
|
||||
<< " (last step: " << _lapDuration.elapsed() << " msec"
|
||||
<< ", total: " << _totalDuration.elapsed() << " msec)" << endl;
|
||||
_file->close();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QScopedPointer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "syncfileitem.h"
|
||||
#include "utility.h"
|
||||
|
||||
namespace OCC {
|
||||
class SyncFileItem;
|
||||
@@ -32,10 +32,9 @@ class SyncRunFileLog
|
||||
{
|
||||
public:
|
||||
SyncRunFileLog();
|
||||
void start( const QString& folderPath );
|
||||
void start( const QString& folderPath, const Utility::StopWatch& stopWatch );
|
||||
void logItem( const SyncFileItem& item );
|
||||
void logLap( const QString& name );
|
||||
void finish();
|
||||
void close();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -46,8 +45,7 @@ private:
|
||||
|
||||
QScopedPointer<QFile> _file;
|
||||
QTextStream _out;
|
||||
QElapsedTimer _totalDuration;
|
||||
QElapsedTimer _lapDuration;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ OwncloudHttpCredsPage::OwncloudHttpCredsPage(QWidget* parent)
|
||||
: AbstractCredentialsWizardPage(),
|
||||
_ui(),
|
||||
_connected(false),
|
||||
_checking(false),
|
||||
_progressIndi(new QProgressIndicator (this))
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
@@ -113,8 +114,6 @@ void OwncloudHttpCredsPage::initializePage()
|
||||
_ui.lePassword->setText(password);
|
||||
}
|
||||
}
|
||||
_ui.tokenLabel->setText(HttpCredentialsGui::requestAppPasswordText(ocWizard->account().data()));
|
||||
_ui.tokenLabel->setVisible(!_ui.tokenLabel->text().isEmpty());
|
||||
_ui.leUsername->setFocus();
|
||||
}
|
||||
|
||||
@@ -132,20 +131,14 @@ bool OwncloudHttpCredsPage::validatePage()
|
||||
|
||||
if (!_connected) {
|
||||
_ui.errorLabel->setVisible(false);
|
||||
_checking = true;
|
||||
startSpinner();
|
||||
|
||||
// Reset cookies to ensure the username / password is actually used
|
||||
OwncloudWizard* ocWizard = qobject_cast< OwncloudWizard* >(wizard());
|
||||
ocWizard->account()->clearCookieJar();
|
||||
|
||||
emit completeChanged();
|
||||
emit connectToOCUrl(field("OCUrl").toString().simplified());
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// Reset, to require another connection attempt next time
|
||||
_connected = false;
|
||||
|
||||
_checking = false;
|
||||
emit completeChanged();
|
||||
stopSpinner();
|
||||
return true;
|
||||
@@ -158,9 +151,9 @@ int OwncloudHttpCredsPage::nextId() const
|
||||
return WizardCommon::Page_AdvancedSetup;
|
||||
}
|
||||
|
||||
void OwncloudHttpCredsPage::setConnected()
|
||||
void OwncloudHttpCredsPage::setConnected( bool comp )
|
||||
{
|
||||
_connected = true;
|
||||
_connected = comp;
|
||||
stopSpinner ();
|
||||
}
|
||||
|
||||
@@ -186,6 +179,7 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
|
||||
_ui.errorLabel->setVisible(true);
|
||||
_ui.errorLabel->setText(err);
|
||||
}
|
||||
_checking = false;
|
||||
emit completeChanged();
|
||||
stopSpinner();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
void cleanupPage() Q_DECL_OVERRIDE;
|
||||
bool validatePage() Q_DECL_OVERRIDE;
|
||||
int nextId() const Q_DECL_OVERRIDE;
|
||||
void setConnected();
|
||||
void setConnected(bool connected);
|
||||
void setErrorString( const QString& err );
|
||||
|
||||
Q_SIGNALS:
|
||||
@@ -53,6 +53,7 @@ private:
|
||||
|
||||
Ui_OwncloudHttpCredsPage _ui;
|
||||
bool _connected;
|
||||
bool _checking;
|
||||
QProgressIndicator* _progressIndi;
|
||||
OwncloudWizard* _ocWizard;
|
||||
};
|
||||
|
||||
@@ -7,30 +7,14 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>248</height>
|
||||
<height>196</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="resultLayout"/>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="topLabel">
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -46,23 +30,7 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="1" column="1">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="usernameLabel">
|
||||
@@ -75,7 +43,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="passwordLabel">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>&Password</string>
|
||||
</property>
|
||||
@@ -87,7 +55,7 @@
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="errorLabel">
|
||||
<property name="text">
|
||||
<string notr="true">Error Label</string>
|
||||
<string>Error Label</string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
@@ -106,7 +74,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -119,23 +87,42 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<widget class="QLabel" name="bottomLabel">
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="tokenLabel">
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="resultLayout"/>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="topLabel">
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QLabel" name="bottomLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
#include "wizard/owncloudwizard.h"
|
||||
#include "wizard/owncloudsetuppage.h"
|
||||
#include "wizard/owncloudhttpcredspage.h"
|
||||
#ifndef NO_SHIBBOLETH
|
||||
#include "wizard/owncloudshibbolethcredspage.h"
|
||||
#endif
|
||||
#include "wizard/owncloudadvancedsetuppage.h"
|
||||
#include "wizard/owncloudwizardresultpage.h"
|
||||
|
||||
@@ -41,9 +39,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
||||
_account(0),
|
||||
_setupPage(new OwncloudSetupPage(this)),
|
||||
_httpCredsPage(new OwncloudHttpCredsPage(this)),
|
||||
#ifndef NO_SHIBBOLETH
|
||||
_shibbolethCredsPage(new OwncloudShibbolethCredsPage),
|
||||
#endif
|
||||
_advancedSetupPage(new OwncloudAdvancedSetupPage),
|
||||
_resultPage(new OwncloudWizardResultPage),
|
||||
_credentialsPage(0),
|
||||
@@ -52,9 +48,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setPage(WizardCommon::Page_ServerSetup, _setupPage);
|
||||
setPage(WizardCommon::Page_HttpCreds, _httpCredsPage);
|
||||
#ifndef NO_SHIBBOLETH
|
||||
setPage(WizardCommon::Page_ShibbolethCreds, _shibbolethCredsPage);
|
||||
#endif
|
||||
setPage(WizardCommon::Page_AdvancedSetup, _advancedSetupPage);
|
||||
setPage(WizardCommon::Page_Result, _resultPage);
|
||||
|
||||
@@ -67,9 +61,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
||||
connect( this, SIGNAL(currentIdChanged(int)), SLOT(slotCurrentPageChanged(int)));
|
||||
connect( _setupPage, SIGNAL(determineAuthType(QString)), SIGNAL(determineAuthType(QString)));
|
||||
connect( _httpCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString)));
|
||||
#ifndef NO_SHIBBOLETH
|
||||
connect( _shibbolethCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString)));
|
||||
#endif
|
||||
connect( _advancedSetupPage, SIGNAL(createLocalAndRemoteFolders(QString, QString)),
|
||||
SIGNAL(createLocalAndRemoteFolders(QString, QString)));
|
||||
connect(this, SIGNAL(customButtonClicked(int)), this, SIGNAL(skipFolderConfiguration()));
|
||||
@@ -133,14 +125,12 @@ void OwncloudWizard::successfulStep()
|
||||
|
||||
switch (id) {
|
||||
case WizardCommon::Page_HttpCreds:
|
||||
_httpCredsPage->setConnected();
|
||||
_httpCredsPage->setConnected(true);
|
||||
break;
|
||||
|
||||
#ifndef NO_SHIBBOLETH
|
||||
case WizardCommon::Page_ShibbolethCreds:
|
||||
_shibbolethCredsPage->setConnected();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case WizardCommon::Page_AdvancedSetup:
|
||||
_advancedSetupPage->directoriesCreated();
|
||||
@@ -158,12 +148,9 @@ void OwncloudWizard::successfulStep()
|
||||
void OwncloudWizard::setAuthType(WizardCommon::AuthType type)
|
||||
{
|
||||
_setupPage->setAuthType(type);
|
||||
#ifndef NO_SHIBBOLETH
|
||||
if (type == WizardCommon::Shibboleth) {
|
||||
_credentialsPage = _shibbolethCredsPage;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
_credentialsPage = _httpCredsPage;
|
||||
}
|
||||
next();
|
||||
@@ -185,6 +172,12 @@ void OwncloudWizard::slotCurrentPageChanged( int id )
|
||||
}
|
||||
|
||||
setOption(QWizard::HaveCustomButton1, id == WizardCommon::Page_AdvancedSetup);
|
||||
|
||||
if (id == WizardCommon::Page_AdvancedSetup) {
|
||||
// Going back from this page messes the state as the account is created already
|
||||
button(QWizard::BackButton)->setDisabled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OwncloudWizard::displayError( const QString& msg, bool retryHTTPonly )
|
||||
|
||||
@@ -25,9 +25,7 @@ namespace OCC {
|
||||
|
||||
class OwncloudSetupPage;
|
||||
class OwncloudHttpCredsPage;
|
||||
#ifndef NO_SHIBBOLETH
|
||||
class OwncloudShibbolethCredsPage;
|
||||
#endif
|
||||
class OwncloudAdvancedSetupPage;
|
||||
class OwncloudWizardResultPage;
|
||||
class AbstractCredentials;
|
||||
@@ -90,9 +88,7 @@ private:
|
||||
AccountPtr _account;
|
||||
OwncloudSetupPage* _setupPage;
|
||||
OwncloudHttpCredsPage* _httpCredsPage;
|
||||
#ifndef NO_SHIBBOLETH
|
||||
OwncloudShibbolethCredsPage* _shibbolethCredsPage;
|
||||
#endif
|
||||
OwncloudAdvancedSetupPage* _advancedSetupPage;
|
||||
OwncloudWizardResultPage* _resultPage;
|
||||
AbstractCredentialsWizardPage* _credentialsPage;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OCC {
|
||||
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _timedout(false)
|
||||
, _followRedirects(true)
|
||||
, _followRedirects(false)
|
||||
, _account(account)
|
||||
, _ignoreCredentialFailure(false)
|
||||
, _reply(0)
|
||||
|
||||
@@ -106,7 +106,7 @@ void ConnectionValidator::slotCheckServerAndAuth()
|
||||
checkJob->setTimeout(timeoutToUseMsec);
|
||||
checkJob->setIgnoreCredentialFailure(true);
|
||||
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
|
||||
connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*)));
|
||||
connect(checkJob, SIGNAL(instanceNotFound(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*)));
|
||||
connect(checkJob, SIGNAL(timeout(QUrl)), SLOT(slotJobTimeout(QUrl)));
|
||||
checkJob->start();
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ int get_errno_from_http_errcode( int err, const QString & reason ) {
|
||||
|
||||
|
||||
DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -218,15 +218,10 @@ void DiscoverySingleDirectoryJob::start()
|
||||
{
|
||||
// Start the actual HTTP job
|
||||
LsColJob *lsColJob = new LsColJob(_account, _subPath, this);
|
||||
|
||||
QList<QByteArray> props;
|
||||
props << "resourcetype" << "getlastmodified" << "getcontentlength" << "getetag"
|
||||
<< "http://owncloud.org/ns:id" << "http://owncloud.org/ns:downloadURL"
|
||||
<< "http://owncloud.org/ns:dDC" << "http://owncloud.org/ns:permissions";
|
||||
if (_isRootPath)
|
||||
props << "http://owncloud.org/ns:data-fingerprint";
|
||||
|
||||
lsColJob->setProperties(props);
|
||||
lsColJob->setProperties(QList<QByteArray>() << "resourcetype" << "getlastmodified"
|
||||
<< "getcontentlength" << "getetag" << "http://owncloud.org/ns:id"
|
||||
<< "http://owncloud.org/ns:downloadURL" << "http://owncloud.org/ns:dDC"
|
||||
<< "http://owncloud.org/ns:permissions");
|
||||
|
||||
QObject::connect(lsColJob, SIGNAL(directoryListingIterated(QString,QMap<QString,QString>)),
|
||||
this, SLOT(directoryListingIteratedSlot(QString,QMap<QString,QString>)));
|
||||
@@ -304,14 +299,12 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
||||
{
|
||||
//qDebug() << Q_FUNC_INFO << _subPath << file << map.count() << map.keys() << _account->davPath() << _lsColJob->reply()->request().url().path();
|
||||
if (!_ignoredFirst) {
|
||||
// The first entry is for the folder itself, we should process it differently.
|
||||
// First result is the directory itself. Maybe should have a better check for that? FIXME
|
||||
_ignoredFirst = true;
|
||||
if (map.contains("permissions")) {
|
||||
emit firstDirectoryPermissions(map.value("permissions"));
|
||||
}
|
||||
if (map.contains("data-fingerprint")) {
|
||||
_dataFingerprint = map.value("data-fingerprint").toUtf8();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Remove <webDAV-Url>/folder/ from <webDAV-Url>/folder/subfile.txt
|
||||
file.remove(0, _lsColJob->reply()->request().url().path().length());
|
||||
@@ -433,11 +426,6 @@ void DiscoveryMainThread::doOpendirSlot(const QString &subPath, DiscoveryDirecto
|
||||
this, SIGNAL(etagConcatenation(QString)));
|
||||
QObject::connect(_singleDirJob, SIGNAL(etag(QString)),
|
||||
this, SIGNAL(etag(QString)));
|
||||
|
||||
if (!_firstFolderProcessed) {
|
||||
_singleDirJob->setIsRootPath();
|
||||
}
|
||||
|
||||
_singleDirJob->start();
|
||||
}
|
||||
|
||||
@@ -453,12 +441,7 @@ void DiscoveryMainThread::singleDirectoryJobResultSlot(const QList<FileStatPoint
|
||||
_currentDiscoveryDirectoryResult->list = result;
|
||||
_currentDiscoveryDirectoryResult->code = 0;
|
||||
_currentDiscoveryDirectoryResult->listIndex = 0;
|
||||
_currentDiscoveryDirectoryResult = 0; // the sync thread owns it now
|
||||
|
||||
if (!_firstFolderProcessed) {
|
||||
_firstFolderProcessed = true;
|
||||
_dataFingerprint = _singleDirJob->_dataFingerprint;
|
||||
}
|
||||
_currentDiscoveryDirectoryResult = 0; // the sync thread owns it now
|
||||
|
||||
_discoveryJob->_vioMutex.lock();
|
||||
_discoveryJob->_vioWaitCondition.wakeAll();
|
||||
|
||||
@@ -81,8 +81,6 @@ class DiscoverySingleDirectoryJob : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent = 0);
|
||||
// Specify thgat this is the root and we need to check the data-fingerprint
|
||||
void setIsRootPath() { _isRootPath = true; }
|
||||
void start();
|
||||
void abort();
|
||||
// This is not actually a network job, it is just a job
|
||||
@@ -102,15 +100,8 @@ private:
|
||||
QString _etagConcatenation;
|
||||
QString _firstEtag;
|
||||
AccountPtr _account;
|
||||
// The first result is for the directory itself and need to be ignored.
|
||||
// This flag is true if it was already ignored.
|
||||
bool _ignoredFirst;
|
||||
// Set to true if this is the root path and we need to check the data-fingerprint
|
||||
bool _isRootPath;
|
||||
QPointer<LsColJob> _lsColJob;
|
||||
|
||||
public:
|
||||
QByteArray _dataFingerprint;
|
||||
};
|
||||
|
||||
// Lives in main thread. Deleted by the SyncEngine
|
||||
@@ -124,16 +115,13 @@ class DiscoveryMainThread : public QObject {
|
||||
AccountPtr _account;
|
||||
DiscoveryDirectoryResult *_currentDiscoveryDirectoryResult;
|
||||
qint64 *_currentGetSizeResult;
|
||||
bool _firstFolderProcessed;
|
||||
|
||||
public:
|
||||
DiscoveryMainThread(AccountPtr account) : QObject(), _account(account),
|
||||
_currentDiscoveryDirectoryResult(0), _currentGetSizeResult(0), _firstFolderProcessed(false)
|
||||
_currentDiscoveryDirectoryResult(0), _currentGetSizeResult(0)
|
||||
{ }
|
||||
void abort();
|
||||
|
||||
QByteArray _dataFingerprint;
|
||||
|
||||
|
||||
public slots:
|
||||
// From DiscoveryJob:
|
||||
|
||||
@@ -46,13 +46,6 @@ void ExcludedFiles::addExcludeFilePath(const QString& path)
|
||||
_excludeFiles.insert(path);
|
||||
}
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
void ExcludedFiles::addExcludeExpr(const QString &expr)
|
||||
{
|
||||
_csync_exclude_add(_excludesPtr, expr.toLatin1().constData());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ExcludedFiles::reloadExcludes()
|
||||
{
|
||||
c_strlist_destroy(*_excludesPtr);
|
||||
|
||||
@@ -57,10 +57,6 @@ public:
|
||||
const QString& basePath,
|
||||
bool excludeHidden) const;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
void addExcludeExpr(const QString &expr);
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Reloads the exclude patterns from the registered paths.
|
||||
|
||||
@@ -359,6 +359,7 @@ CheckServerJob::CheckServerJob(AccountPtr account, QObject *parent)
|
||||
: AbstractNetworkJob(account, QLatin1String(statusphpC) , parent)
|
||||
, _subdirFallback(false)
|
||||
{
|
||||
_followRedirects = true;
|
||||
setIgnoreCredentialFailure(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -201,12 +201,12 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
|
||||
downloadItem->_instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
}
|
||||
downloadItem->_direction = SyncFileItem::Down;
|
||||
newJob = new PropagateDownloadFile(_propagator, downloadItem);
|
||||
newJob = new PropagateDownloadFileQNAM(_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->_instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
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
|
||||
@@ -265,14 +265,20 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItemPtr &item) {
|
||||
} //fall through
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
case CSYNC_INSTRUCTION_CONFLICT:
|
||||
if (item->_direction != SyncFileItem::Up) {
|
||||
auto job = new PropagateDownloadFile(this, item);
|
||||
job->setDeleteExistingFolder(deleteExisting);
|
||||
return job;
|
||||
} else {
|
||||
auto job = new PropagateUploadFile(this, item);
|
||||
job->setDeleteExisting(deleteExisting);
|
||||
return job;
|
||||
if (item->_isDirectory) {
|
||||
// Should we set the mtime?
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
if (item->_direction != SyncFileItem::Up) {
|
||||
auto job = new PropagateDownloadFileQNAM(this, item);
|
||||
job->setDeleteExistingFolder(deleteExisting);
|
||||
return job;
|
||||
} else {
|
||||
auto job = new PropagateUploadFileQNAM(this, item);
|
||||
job->setDeleteExisting(deleteExisting);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (item->_direction == SyncFileItem::Up) {
|
||||
@@ -371,8 +377,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
||||
// NOTE: Currently this means that we don't update those etag at all in this sync,
|
||||
// but it should not be a problem, they will be updated in the next sync.
|
||||
for (int i = 0; i < directories.size(); ++i) {
|
||||
if (directories[i].second->_item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA)
|
||||
directories[i].second->_item->_instruction = CSYNC_INSTRUCTION_NONE;
|
||||
directories[i].second->_item->_should_update_metadata = false;
|
||||
}
|
||||
} else {
|
||||
PropagateDirectory* currentDirJob = directories.top().second;
|
||||
@@ -397,7 +402,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_rootJob.data(), SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished(SyncFileItem::Status)));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished()));
|
||||
connect(_rootJob.data(), SIGNAL(ready()), this, SLOT(scheduleNextJob()), Qt::QueuedConnection);
|
||||
|
||||
qDebug() << "Using QNAM/HTTP parallel code path";
|
||||
@@ -537,6 +542,27 @@ void OwncloudPropagator::scheduleNextJob()
|
||||
}
|
||||
}
|
||||
|
||||
void OwncloudPropagator::addTouchedFile(const QString& fn)
|
||||
{
|
||||
QString file = QDir::cleanPath(fn);
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
QMutexLocker lock(&_touchedFilesMutex);
|
||||
_touchedFiles.insert(file, timer);
|
||||
}
|
||||
|
||||
qint64 OwncloudPropagator::timeSinceFileTouched(const QString& fn) const
|
||||
{
|
||||
QMutexLocker lock(&_touchedFilesMutex);
|
||||
if (! _touchedFiles.contains(fn)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _touchedFiles[fn].elapsed();
|
||||
}
|
||||
|
||||
AccountPtr OwncloudPropagator::account() const
|
||||
{
|
||||
return _account;
|
||||
@@ -640,6 +666,7 @@ void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
||||
(sender() == _firstJob.data() && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||
abort();
|
||||
_state = Finished;
|
||||
emit itemCompleted(*_item, *this);
|
||||
emit finished(status);
|
||||
return;
|
||||
} else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
|
||||
@@ -668,15 +695,16 @@ void PropagateDirectory::finalize()
|
||||
bool ok = true;
|
||||
if (!_item->isEmpty() && _hasError == SyncFileItem::NoStatus) {
|
||||
if( !_item->_renameTarget.isEmpty() ) {
|
||||
if(_item->_instruction == CSYNC_INSTRUCTION_RENAME
|
||||
&& _item->_originalFile != _item->_renameTarget) {
|
||||
// Remove the stale entries from the database.
|
||||
_propagator->_journal->deleteFileRecord(_item->_originalFile, true);
|
||||
}
|
||||
|
||||
_item->_file = _item->_renameTarget;
|
||||
}
|
||||
|
||||
// For new directories we always want to update the etag once
|
||||
// the directory has been propagated. Otherwise the directory
|
||||
// could appear locally without being added to the database.
|
||||
if (_item->_instruction == CSYNC_INSTRUCTION_RENAME
|
||||
|| _item->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| _item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA) {
|
||||
if (_item->_should_update_metadata && _item->_instruction != CSYNC_INSTRUCTION_REMOVE) {
|
||||
if (PropagateRemoteMkdir* mkdir = qobject_cast<PropagateRemoteMkdir*>(_firstJob.data())) {
|
||||
// special case from MKDIR, get the fileId from the job there
|
||||
if (_item->_fileId.isEmpty() && !mkdir->_item->_fileId.isEmpty()) {
|
||||
@@ -693,6 +721,13 @@ void PropagateDirectory::finalize()
|
||||
}
|
||||
}
|
||||
_state = Finished;
|
||||
// Just to make sure that the SocketApi will know by looking in
|
||||
// SyncEngine::_syncedItems that this folder is done synchronizing.
|
||||
if (ok) {
|
||||
_item->_status = SyncFileItem::Success;
|
||||
}
|
||||
|
||||
emit itemCompleted(*_item, *this);
|
||||
emit finished(_item->_status);
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ public:
|
||||
if (_rootJob) {
|
||||
_rootJob->abort();
|
||||
}
|
||||
emitFinished(SyncFileItem::NormalError);
|
||||
emitFinished();
|
||||
}
|
||||
|
||||
// timeout in seconds
|
||||
@@ -330,6 +330,18 @@ public:
|
||||
/** returns the size of chunks in bytes */
|
||||
static quint64 chunkSize();
|
||||
|
||||
/** Records that a file was touched by a job.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
void addTouchedFile(const QString& fn);
|
||||
|
||||
/** Get the ms since a file was touched, or -1 if it wasn't.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
qint64 timeSinceFileTouched(const QString& fn) const;
|
||||
|
||||
AccountPtr account() const;
|
||||
|
||||
enum DiskSpaceResult
|
||||
@@ -349,9 +361,9 @@ public:
|
||||
private slots:
|
||||
|
||||
/** Emit the finished signal and make sure it is only emitted once */
|
||||
void emitFinished(SyncFileItem::Status status) {
|
||||
void emitFinished() {
|
||||
if (!_finishedEmited)
|
||||
emit finished(status == SyncFileItem::Success);
|
||||
emit finished();
|
||||
_finishedEmited = true;
|
||||
}
|
||||
|
||||
@@ -360,29 +372,23 @@ private slots:
|
||||
signals:
|
||||
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||
void progress(const SyncFileItem&, quint64 bytes);
|
||||
void finished(bool success);
|
||||
void finished();
|
||||
|
||||
/** Emitted when propagation has problems with a locked file. */
|
||||
void seenLockedFile(const QString &fileName);
|
||||
|
||||
/** Emitted when propagation touches a file.
|
||||
*
|
||||
* Used to track our own file modifications such that notifications
|
||||
* from the file watcher about these can be ignored.
|
||||
*/
|
||||
void touchedFile(const QString &fileName);
|
||||
|
||||
private:
|
||||
|
||||
AccountPtr _account;
|
||||
|
||||
/** Stores the time since a job touched a file. */
|
||||
QHash<QString, QElapsedTimer> _touchedFiles;
|
||||
mutable QMutex _touchedFilesMutex;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
// access to signals which are protected in Qt4
|
||||
friend class PropagateDownloadFile;
|
||||
friend class PropagateUploadFile;
|
||||
friend class PropagateLocalMkdir;
|
||||
friend class PropagateLocalRename;
|
||||
friend class PropagateRemoteMove;
|
||||
friend class PropagateDownloadFileQNAM;
|
||||
friend class PropagateUploadFileQNAM;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -303,11 +303,6 @@ void SqlQuery::bindValue(int pos, const QVariant& value)
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
break; }
|
||||
case QVariant::ByteArray: {
|
||||
auto ba = value.toByteArray();
|
||||
res = sqlite3_bind_text(_stmt, pos, ba.constData(), ba.size(), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
@@ -317,7 +312,7 @@ void SqlQuery::bindValue(int pos, const QVariant& value)
|
||||
}
|
||||
}
|
||||
if (res != SQLITE_OK) {
|
||||
qDebug() << Q_FUNC_INFO << "ERROR" << value << res;
|
||||
qDebug() << Q_FUNC_INFO << "ERROR" << value.toString() << res;
|
||||
}
|
||||
Q_ASSERT( res == SQLITE_OK );
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ QString Progress::asResultString( const SyncFileItem& item)
|
||||
return QCoreApplication::translate( "progress", "Filesystem access error");
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
return QCoreApplication::translate( "progress", "Error");
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
return QCoreApplication::translate( "progress", "Updated local metadata");
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
return QCoreApplication::translate( "progress", "Unknown");
|
||||
@@ -78,8 +76,6 @@ QString Progress::asActionString( const SyncFileItem &item )
|
||||
return QCoreApplication::translate( "progress", "error");
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
return QCoreApplication::translate( "progress", "error");
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
return QCoreApplication::translate( "progress", "updating local metadata");
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
break;
|
||||
@@ -163,10 +159,17 @@ static bool shouldCountProgress(const SyncFileItem &item)
|
||||
{
|
||||
const auto instruction = item._instruction;
|
||||
|
||||
// Skip any ignored, error or non-propagated files and directories.
|
||||
if (instruction == CSYNC_INSTRUCTION_NONE
|
||||
|| instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
|| instruction == CSYNC_INSTRUCTION_IGNORE
|
||||
// Don't worry about directories that won't have propagation
|
||||
// jobs associated with them.
|
||||
if (item._isDirectory
|
||||
&& (instruction == CSYNC_INSTRUCTION_NONE
|
||||
|| instruction == CSYNC_INSTRUCTION_SYNC
|
||||
|| instruction == CSYNC_INSTRUCTION_CONFLICT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip any ignored or error files, we do nothing with them.
|
||||
if (instruction == CSYNC_INSTRUCTION_IGNORE
|
||||
|| instruction == CSYNC_INSTRUCTION_ERROR) {
|
||||
return false;
|
||||
}
|
||||
@@ -276,6 +279,13 @@ ProgressInfo::Estimates ProgressInfo::totalProgress() const
|
||||
// assume the remaining transfer will be done with the highest speed
|
||||
// we've seen.
|
||||
|
||||
// This assumes files and transfers finish as quickly as possible
|
||||
// *but* note that maxPerSecond could be serious underestimates
|
||||
// (if we never got to fully excercise transfer or files/second)
|
||||
quint64 optimisticEta =
|
||||
_fileProgress.remaining() / _maxFilesPerSecond * 1000
|
||||
+ _sizeProgress.remaining() / _maxBytesPerSecond * 1000;
|
||||
|
||||
// Compute a value that is 0 when fps is <=L*max and 1 when fps is >=U*max
|
||||
double fps = _fileProgress._progressPerSec;
|
||||
double fpsL = 0.5;
|
||||
@@ -299,26 +309,11 @@ ProgressInfo::Estimates ProgressInfo::totalProgress() const
|
||||
|
||||
double beOptimistic = nearMaxFps * slowTransfer;
|
||||
size.estimatedEta = (1.0 - beOptimistic) * size.estimatedEta
|
||||
+ beOptimistic * optimisticEta();
|
||||
+ beOptimistic * optimisticEta;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
quint64 ProgressInfo::optimisticEta() const
|
||||
{
|
||||
// This assumes files and transfers finish as quickly as possible
|
||||
// *but* note that maxPerSecond could be serious underestimate
|
||||
// (if we never got to fully excercise transfer or files/second)
|
||||
|
||||
return _fileProgress.remaining() / _maxFilesPerSecond * 1000
|
||||
+ _sizeProgress.remaining() / _maxBytesPerSecond * 1000;
|
||||
}
|
||||
|
||||
bool ProgressInfo::trustEta() const
|
||||
{
|
||||
return totalProgress().estimatedEta < 100 * optimisticEta();
|
||||
}
|
||||
|
||||
ProgressInfo::Estimates ProgressInfo::fileProgress(const SyncFileItem &item) const
|
||||
{
|
||||
return _currentItems[item._file]._progress.estimates();
|
||||
|
||||
@@ -164,22 +164,6 @@ public:
|
||||
*/
|
||||
Estimates totalProgress() const;
|
||||
|
||||
/**
|
||||
* Get the optimistic eta.
|
||||
*
|
||||
* This value is based on the highest observed transfer bandwidth
|
||||
* and files-per-second speed.
|
||||
*/
|
||||
quint64 optimisticEta() const;
|
||||
|
||||
/**
|
||||
* Whether the remaining-time estimate is trusted.
|
||||
*
|
||||
* We don't trust it if it is hugely above the optimistic estimate.
|
||||
* See #5046.
|
||||
*/
|
||||
bool trustEta() const;
|
||||
|
||||
/**
|
||||
* Get the current file completion estimate structure
|
||||
*/
|
||||
|
||||
@@ -99,6 +99,7 @@ void GETFileJob::start() {
|
||||
} else {
|
||||
// Use direct URL
|
||||
setReply(davRequest("GET", _directDownloadUrl, req));
|
||||
_followRedirects = true; // (follow redirections for the direct download)
|
||||
}
|
||||
setupConnections(reply());
|
||||
|
||||
@@ -304,7 +305,7 @@ QString GETFileJob::errorString() const
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::start()
|
||||
void PropagateDownloadFileQNAM::start()
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||
return;
|
||||
@@ -418,7 +419,7 @@ void PropagateDownloadFile::start()
|
||||
_job->start();
|
||||
}
|
||||
|
||||
qint64 PropagateDownloadFile::committedDiskSpace() const
|
||||
qint64 PropagateDownloadFileQNAM::committedDiskSpace() const
|
||||
{
|
||||
if (_state == Running) {
|
||||
return qBound(0ULL, _item->_size - _resumeStart - _downloadProgress, _item->_size);
|
||||
@@ -426,13 +427,13 @@ qint64 PropagateDownloadFile::committedDiskSpace() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::setDeleteExistingFolder(bool enabled)
|
||||
void PropagateDownloadFileQNAM::setDeleteExistingFolder(bool enabled)
|
||||
{
|
||||
_deleteExisting = enabled;
|
||||
}
|
||||
|
||||
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
|
||||
void PropagateDownloadFile::slotGetFinished()
|
||||
void PropagateDownloadFileQNAM::slotGetFinished()
|
||||
{
|
||||
_propagator->_activeJobList.removeOne(this);
|
||||
|
||||
@@ -565,14 +566,14 @@ void PropagateDownloadFile::slotGetFinished()
|
||||
validator->start(_tmpFile.fileName(), checksumHeader);
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::slotChecksumFail( const QString& errMsg )
|
||||
void PropagateDownloadFileQNAM::slotChecksumFail( const QString& errMsg )
|
||||
{
|
||||
FileSystem::remove(_tmpFile.fileName());
|
||||
_propagator->_anotherSyncNeeded = true;
|
||||
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::deleteExistingFolder()
|
||||
void PropagateDownloadFileQNAM::deleteExistingFolder()
|
||||
{
|
||||
QString existingDir = _propagator->getFilePath(_item->_file);
|
||||
if (!QFileInfo(existingDir).isDir()) {
|
||||
@@ -591,8 +592,8 @@ void PropagateDownloadFile::deleteExistingFolder()
|
||||
QString conflictDir = FileSystem::makeConflictFileName(
|
||||
existingDir, Utility::qDateTimeFromTime_t(_item->_modtime));
|
||||
|
||||
emit _propagator->touchedFile(existingDir);
|
||||
emit _propagator->touchedFile(conflictDir);
|
||||
_propagator->addTouchedFile(existingDir);
|
||||
_propagator->addTouchedFile(conflictDir);
|
||||
QString renameError;
|
||||
if (!FileSystem::rename(existingDir, conflictDir, &renameError)) {
|
||||
done(SyncFileItem::NormalError, renameError);
|
||||
@@ -616,30 +617,47 @@ static QString makeRecallFileName(const QString &fn)
|
||||
return recallFileName;
|
||||
}
|
||||
|
||||
static void handleRecallFile(const QString &fn)
|
||||
void handleRecallFile(const QString& filePath, const QString& folderPath, SyncJournalDb& journal)
|
||||
{
|
||||
qDebug() << "handleRecallFile: " << fn;
|
||||
qDebug() << "handleRecallFile: " << filePath;
|
||||
|
||||
FileSystem::setFileHidden(fn, true);
|
||||
FileSystem::setFileHidden(filePath, true);
|
||||
|
||||
QFile file(fn);
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "Could not open recall file" << file.errorString();
|
||||
return;
|
||||
}
|
||||
QFileInfo existingFile(fn);
|
||||
QDir thisDir = existingFile.dir();
|
||||
QFileInfo existingFile(filePath);
|
||||
QDir baseDir = existingFile.dir();
|
||||
|
||||
while (!file.atEnd()) {
|
||||
QByteArray line = file.readLine();
|
||||
line.chop(1); // remove trailing \n
|
||||
QString fpath = thisDir.filePath(line);
|
||||
QString rpath = makeRecallFileName(fpath);
|
||||
|
||||
qDebug() << "Copy recall file: " << fpath << " -> " << rpath;
|
||||
QString recalledFile = QDir::cleanPath(baseDir.filePath(line));
|
||||
if (!recalledFile.startsWith(folderPath) || !recalledFile.startsWith(baseDir.path())) {
|
||||
qDebug() << "Ignoring recall of " << recalledFile;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Path of the recalled file in the local folder
|
||||
QString localRecalledFile = recalledFile.mid(folderPath.size());
|
||||
|
||||
SyncJournalFileRecord record = journal.getFileRecord(localRecalledFile);
|
||||
if (!record.isValid()) {
|
||||
qDebug() << "No db entry for recall of" << localRecalledFile;
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "Recalling" << localRecalledFile << "Checksum:" << record._contentChecksumType << record._contentChecksum;
|
||||
|
||||
QString targetPath = makeRecallFileName(recalledFile);
|
||||
|
||||
qDebug() << "Copy recall file: " << recalledFile << " -> " << targetPath;
|
||||
// Remove the target first, QFile::copy will not overwrite it.
|
||||
FileSystem::remove(rpath);
|
||||
QFile::copy(fpath, rpath);
|
||||
FileSystem::remove(targetPath);
|
||||
QFile::copy(recalledFile, targetPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,7 +672,7 @@ static void preserveGroupOwnership(const QString& fileName, const QFileInfo& fi)
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
void PropagateDownloadFile::transmissionChecksumValidated(const QByteArray &checksumType, const QByteArray &checksum)
|
||||
void PropagateDownloadFileQNAM::transmissionChecksumValidated(const QByteArray &checksumType, const QByteArray &checksum)
|
||||
{
|
||||
const auto theContentChecksumType = contentChecksumType();
|
||||
|
||||
@@ -675,7 +693,7 @@ void PropagateDownloadFile::transmissionChecksumValidated(const QByteArray &chec
|
||||
computeChecksum->start(_tmpFile.fileName());
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum)
|
||||
void PropagateDownloadFileQNAM::contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum)
|
||||
{
|
||||
_item->_contentChecksum = checksum;
|
||||
_item->_contentChecksumType = checksumType;
|
||||
@@ -683,7 +701,7 @@ void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumTy
|
||||
downloadFinished();
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::downloadFinished()
|
||||
void PropagateDownloadFileQNAM::downloadFinished()
|
||||
{
|
||||
QString fn = _propagator->getFilePath(_item->_file);
|
||||
|
||||
@@ -753,7 +771,7 @@ void PropagateDownloadFile::downloadFinished()
|
||||
}
|
||||
|
||||
QString error;
|
||||
emit _propagator->touchedFile(fn);
|
||||
_propagator->addTouchedFile(fn);
|
||||
// The fileChanged() check is done above to generate better error messages.
|
||||
if (!FileSystem::uncheckedRenameReplace(_tmpFile.fileName(), fn, &error)) {
|
||||
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
||||
@@ -796,8 +814,10 @@ void PropagateDownloadFile::downloadFinished()
|
||||
done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
|
||||
|
||||
// handle the special recall file
|
||||
if(_item->_file == QLatin1String(".sys.admin#recall#") || _item->_file.endsWith("/.sys.admin#recall#")) {
|
||||
handleRecallFile(fn);
|
||||
if(!_item->_remotePerm.contains("S")
|
||||
&& (_item->_file == QLatin1String(".sys.admin#recall#")
|
||||
|| _item->_file.endsWith("/.sys.admin#recall#"))) {
|
||||
handleRecallFile(fn, _propagator->_localDir, *_propagator->_journal);
|
||||
}
|
||||
|
||||
qint64 duration = _stopwatch.elapsed();
|
||||
@@ -806,7 +826,7 @@ void PropagateDownloadFile::downloadFinished()
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateDownloadFile::slotDownloadProgress(qint64 received, qint64)
|
||||
void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64)
|
||||
{
|
||||
if (!_job) return;
|
||||
_downloadProgress = received;
|
||||
@@ -814,7 +834,7 @@ void PropagateDownloadFile::slotDownloadProgress(qint64 received, qint64)
|
||||
}
|
||||
|
||||
|
||||
void PropagateDownloadFile::abort()
|
||||
void PropagateDownloadFileQNAM::abort()
|
||||
{
|
||||
if (_job && _job->reply())
|
||||
_job->reply()->abort();
|
||||
|
||||
@@ -103,13 +103,13 @@ private slots:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The PropagateDownloadFile class
|
||||
* @brief The PropagateDownloadFileQNAM class
|
||||
* @ingroup libsync
|
||||
*/
|
||||
class PropagateDownloadFile : public PropagateItemJob {
|
||||
class PropagateDownloadFileQNAM : public PropagateItemJob {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PropagateDownloadFile(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
|
||||
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
|
||||
: PropagateItemJob(propagator, item), _resumeStart(0), _downloadProgress(0), _deleteExisting(false) {}
|
||||
void start() Q_DECL_OVERRIDE;
|
||||
qint64 committedDiskSpace() const Q_DECL_OVERRIDE;
|
||||
|
||||
@@ -80,8 +80,8 @@ void PropagateRemoteMove::start()
|
||||
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);
|
||||
_propagator->addTouchedFile(originalFile);
|
||||
_propagator->addTouchedFile(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."));
|
||||
|
||||
@@ -184,7 +184,7 @@ bool PollJob::finished()
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropagateUploadFile::start()
|
||||
void PropagateUploadFileQNAM::start()
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||
return;
|
||||
@@ -205,7 +205,7 @@ void PropagateUploadFile::start()
|
||||
job->start();
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotComputeContentChecksum()
|
||||
void PropagateUploadFileQNAM::slotComputeContentChecksum()
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||
return;
|
||||
@@ -239,12 +239,12 @@ void PropagateUploadFile::slotComputeContentChecksum()
|
||||
computeChecksum->start(filePath);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::setDeleteExisting(bool enabled)
|
||||
void PropagateUploadFileQNAM::setDeleteExisting(bool enabled)
|
||||
{
|
||||
_deleteExisting = enabled;
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotComputeTransmissionChecksum(const QByteArray& contentChecksumType, const QByteArray& contentChecksum)
|
||||
void PropagateUploadFileQNAM::slotComputeTransmissionChecksum(const QByteArray& contentChecksumType, const QByteArray& contentChecksum)
|
||||
{
|
||||
_item->_contentChecksum = contentChecksum;
|
||||
_item->_contentChecksumType = contentChecksumType;
|
||||
@@ -276,7 +276,7 @@ void PropagateUploadFile::slotComputeTransmissionChecksum(const QByteArray& cont
|
||||
computeChecksum->start(filePath);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotStartUpload(const QByteArray& transmissionChecksumType, const QByteArray& transmissionChecksum)
|
||||
void PropagateUploadFileQNAM::slotStartUpload(const QByteArray& transmissionChecksumType, const QByteArray& transmissionChecksum)
|
||||
{
|
||||
// Remove ourselfs from the list of active job, before any posible call to done()
|
||||
// When we start chunks, we will add it again, once for every chunks.
|
||||
@@ -299,7 +299,7 @@ void PropagateUploadFile::slotStartUpload(const QByteArray& transmissionChecksum
|
||||
}
|
||||
_stopWatch.addLapTime(QLatin1String("TransmissionChecksum"));
|
||||
|
||||
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFile::start()
|
||||
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFileQNAM::start()
|
||||
// but a potential checksum calculation could have taken some time during which the file could
|
||||
// have been changed again, so better check again here.
|
||||
|
||||
@@ -476,7 +476,7 @@ void UploadDevice::setChoked(bool b) {
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateUploadFile::startNextChunk()
|
||||
void PropagateUploadFileQNAM::startNextChunk()
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||
return;
|
||||
@@ -607,7 +607,7 @@ void PropagateUploadFile::startNextChunk()
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotPutFinished()
|
||||
void PropagateUploadFileQNAM::slotPutFinished()
|
||||
{
|
||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
@@ -785,7 +785,7 @@ void PropagateUploadFile::slotPutFinished()
|
||||
finalize(*_item);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::finalize(const SyncFileItem ©)
|
||||
void PropagateUploadFileQNAM::finalize(const SyncFileItem ©)
|
||||
{
|
||||
// Normally, copy == _item, but when it comes from the UpdateMTimeAndETagJob, we need to do
|
||||
// some updates
|
||||
@@ -807,7 +807,7 @@ void PropagateUploadFile::finalize(const SyncFileItem ©)
|
||||
done(SyncFileItem::Success);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotUploadProgress(qint64 sent, qint64 total)
|
||||
void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64 total)
|
||||
{
|
||||
// Completion is signaled with sent=0, total=0; avoid accidentally
|
||||
// resetting progress due to the sent being zero by ignoring it.
|
||||
@@ -840,7 +840,7 @@ void PropagateUploadFile::slotUploadProgress(qint64 sent, qint64 total)
|
||||
emit progress(*_item, amount);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::startPollJob(const QString& path)
|
||||
void PropagateUploadFileQNAM::startPollJob(const QString& path)
|
||||
{
|
||||
PollJob* job = new PollJob(_propagator->account(), path, _item,
|
||||
_propagator->_journal, _propagator->_localDir, this);
|
||||
@@ -855,7 +855,7 @@ void PropagateUploadFile::startPollJob(const QString& path)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotPollFinished()
|
||||
void PropagateUploadFileQNAM::slotPollFinished()
|
||||
{
|
||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
@@ -871,12 +871,12 @@ void PropagateUploadFile::slotPollFinished()
|
||||
finalize(*job->_item);
|
||||
}
|
||||
|
||||
void PropagateUploadFile::slotJobDestroyed(QObject* job)
|
||||
void PropagateUploadFileQNAM::slotJobDestroyed(QObject* job)
|
||||
{
|
||||
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job) , _jobs.end());
|
||||
}
|
||||
|
||||
void PropagateUploadFile::abort()
|
||||
void PropagateUploadFileQNAM::abort()
|
||||
{
|
||||
foreach(auto *job, _jobs) {
|
||||
if (job->reply()) {
|
||||
@@ -887,7 +887,7 @@ void PropagateUploadFile::abort()
|
||||
}
|
||||
|
||||
// This function is used whenever there is an error occuring and jobs might be in progress
|
||||
void PropagateUploadFile::abortWithError(SyncFileItem::Status status, const QString &error)
|
||||
void PropagateUploadFileQNAM::abortWithError(SyncFileItem::Status status, const QString &error)
|
||||
{
|
||||
_finished = true;
|
||||
abort();
|
||||
|
||||
@@ -155,10 +155,10 @@ signals:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The PropagateUploadFile class
|
||||
* @brief The PropagateUploadFileQNAM class
|
||||
* @ingroup libsync
|
||||
*/
|
||||
class PropagateUploadFile : public PropagateItemJob {
|
||||
class PropagateUploadFileQNAM : public PropagateItemJob {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
@@ -191,7 +191,7 @@ private:
|
||||
quint64 chunkSize() const { return _propagator->chunkSize(); }
|
||||
|
||||
public:
|
||||
PropagateUploadFile(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
|
||||
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
|
||||
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false), _deleteExisting(false) {}
|
||||
void start() Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ void PropagateLocalMkdir::start()
|
||||
done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
|
||||
return;
|
||||
}
|
||||
emit _propagator->touchedFile(newDirStr);
|
||||
_propagator->addTouchedFile(newDirStr);
|
||||
QDir localDir(_propagator->_localDir);
|
||||
if (!localDir.mkpath(_item->_file)) {
|
||||
done( SyncFileItem::NormalError, tr("could not create folder %1").arg(newDirStr) );
|
||||
@@ -217,8 +217,8 @@ void PropagateLocalRename::start()
|
||||
return;
|
||||
}
|
||||
|
||||
emit _propagator->touchedFile(existingFile);
|
||||
emit _propagator->touchedFile(targetFile);
|
||||
_propagator->addTouchedFile(existingFile);
|
||||
_propagator->addTouchedFile(targetFile);
|
||||
QString renameError;
|
||||
if (!FileSystem::rename(existingFile, targetFile, &renameError)) {
|
||||
done(SyncFileItem::NormalError, renameError);
|
||||
|
||||
@@ -78,10 +78,6 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
||||
{
|
||||
qRegisterMetaType<SyncFileItem>("SyncFileItem");
|
||||
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
|
||||
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
|
||||
|
||||
// Everything in the SyncEngine expects a trailing slash for the localPath.
|
||||
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
|
||||
// We need to reconstruct the url because the path needs to be fully decoded, as csync will re-encode the path:
|
||||
// Remember that csync will just append the filename to the path and pass it to the vio plugin.
|
||||
@@ -99,10 +95,6 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
||||
_excludedFiles.reset(new ExcludedFiles(&_csync_ctx->excludes));
|
||||
_syncFileStatusTracker.reset(new SyncFileStatusTracker(this));
|
||||
|
||||
_clearTouchedFilesTimer.setSingleShot(true);
|
||||
_clearTouchedFilesTimer.setInterval(30*1000);
|
||||
connect(&_clearTouchedFilesTimer, SIGNAL(timeout()), SLOT(slotClearTouchedFiles()));
|
||||
|
||||
_thread.setObjectName("SyncEngine_Thread");
|
||||
}
|
||||
|
||||
@@ -395,6 +387,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
item->_remotePerm = QByteArray(file->remotePerm);
|
||||
}
|
||||
|
||||
item->_should_update_metadata = item->_should_update_metadata || file->should_update_metadata;
|
||||
|
||||
/* The flag "serverHasIgnoredFiles" is true if item in question is a directory
|
||||
* that has children which are ignored in sync, either because the files are
|
||||
* matched by an ignore pattern, or because they are hidden.
|
||||
@@ -439,9 +433,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
case CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS:
|
||||
item->_errorString = tr("Filename contains invalid characters that can not be synced cross platform.");
|
||||
break;
|
||||
case CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE:
|
||||
item->_errorString = tr("Filename contains trailing spaces.");
|
||||
break;
|
||||
case CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME:
|
||||
item->_errorString = tr("Filename is too long.");
|
||||
break;
|
||||
@@ -512,23 +503,10 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
int re = 0;
|
||||
switch(file->instruction) {
|
||||
case CSYNC_INSTRUCTION_NONE: {
|
||||
// Any files that are instruction NONE?
|
||||
if (!isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
|
||||
_hasNoneFiles = true;
|
||||
}
|
||||
// No syncing or update to be done.
|
||||
return re;
|
||||
}
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
dir = SyncFileItem::None;
|
||||
// For directories, metadata-only updates will be done after all their files are propagated.
|
||||
if (!isDirectory) {
|
||||
item->_isDirectory = isDirectory;
|
||||
emit syncItemDiscovered(*item);
|
||||
|
||||
if (remote && item->_should_update_metadata && !isDirectory && item->_instruction == CSYNC_INSTRUCTION_NONE) {
|
||||
// Update the database now already: New remote fileid or Etag or RemotePerm
|
||||
// Or for files that were detected as "resolved conflict".
|
||||
// Or a local inode/mtime change
|
||||
// Or a local inode/mtime change (see localMetadataUpdate below)
|
||||
|
||||
// In case of "resolved conflict": there should have been a conflict because they
|
||||
// both were new, or both had their local mtime or remote etag modified, but the
|
||||
@@ -540,33 +518,47 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
// quick to do and we don't want to create a potentially large number of
|
||||
// mini-jobs later on, we just update metadata right now.
|
||||
|
||||
if (remote) {
|
||||
QString filePath = _localPath + item->_file;
|
||||
QString filePath = _localPath + item->_file;
|
||||
|
||||
// Even if the mtime is different on the server, we always want to keep the mtime from
|
||||
// the file system in the DB, this is to avoid spurious upload on the next sync
|
||||
item->_modtime = file->other.modtime;
|
||||
// same for the size
|
||||
item->_size = file->other.size;
|
||||
// Even if the mtime is different on the server, we always want to keep the mtime from
|
||||
// the file system in the DB, this is to avoid spurious upload on the next sync
|
||||
item->_modtime = file->other.modtime;
|
||||
// same for the size
|
||||
item->_size = file->other.size;
|
||||
|
||||
// If the 'W' remote permission changed, update the local filesystem
|
||||
SyncJournalFileRecord prev = _journal->getFileRecord(item->_file);
|
||||
if (prev.isValid() && prev._remotePerm.contains('W') != item->_remotePerm.contains('W')) {
|
||||
const bool isReadOnly = !item->_remotePerm.contains('W');
|
||||
FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
|
||||
}
|
||||
|
||||
_journal->setFileRecordMetadata(SyncJournalFileRecord(*item, filePath));
|
||||
} else {
|
||||
// The local tree is walked first and doesn't have all the info from the server.
|
||||
// Update only outdated data from the disk.
|
||||
_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode);
|
||||
// If the 'W' remote permission changed, update the local filesystem
|
||||
SyncJournalFileRecord prev = _journal->getFileRecord(item->_file);
|
||||
if (prev.isValid() && prev._remotePerm.contains('W') != item->_remotePerm.contains('W')) {
|
||||
const bool isReadOnly = !item->_remotePerm.contains('W');
|
||||
FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
|
||||
}
|
||||
|
||||
// Technically we're done with this item.
|
||||
_journal->setFileRecordMetadata(SyncJournalFileRecord(*item, filePath));
|
||||
item->_should_update_metadata = false;
|
||||
|
||||
// Technically we're done with this item. See localMetadataUpdate hack below.
|
||||
_syncItemMap.remove(key);
|
||||
}
|
||||
// Any files that are instruction NONE?
|
||||
if (!isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
|
||||
_hasNoneFiles = true;
|
||||
}
|
||||
// We want to still update etags of directories, other NONE
|
||||
// items can be ignored.
|
||||
bool directoryEtagUpdate = isDirectory && file->should_update_metadata;
|
||||
bool localMetadataUpdate = !remote && file->should_update_metadata;
|
||||
if (!directoryEtagUpdate) {
|
||||
item->_isDirectory = isDirectory;
|
||||
if (localMetadataUpdate) {
|
||||
// Hack, we want a local metadata update to happen, but only if the
|
||||
// remote tree doesn't ask us to do some kind of propagation.
|
||||
_syncItemMap.insert(key, item);
|
||||
}
|
||||
emit syncItemDiscovered(*item);
|
||||
return re;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
|
||||
item->_renameTarget = renameTarget;
|
||||
@@ -689,7 +681,6 @@ void SyncEngine::startSync()
|
||||
s_anySyncRunning = true;
|
||||
_syncRunning = true;
|
||||
_anotherSyncNeeded = false;
|
||||
_clearTouchedFilesTimer.stop();
|
||||
|
||||
_progressInfo->reset();
|
||||
|
||||
@@ -726,19 +717,16 @@ void SyncEngine::startSync()
|
||||
|
||||
int fileRecordCount = -1;
|
||||
if (!_journal->exists()) {
|
||||
qDebug() << "===== new sync (no sync journal exists)";
|
||||
qDebug() << "=====sync looks new (no DB exists)";
|
||||
} else {
|
||||
qDebug() << "===== sync with existing sync journal";
|
||||
qDebug() << "=====sync with existing DB";
|
||||
}
|
||||
|
||||
QString verStr("===== Using Qt ");
|
||||
verStr.append( qVersion() );
|
||||
|
||||
qDebug() << "=====Using Qt" << qVersion();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
verStr.append( " SSL library " ).append(QSslSocket::sslLibraryVersionString().toUtf8().data());
|
||||
qDebug() << "=====Using SSL library version"
|
||||
<< QSslSocket::sslLibraryVersionString().toUtf8().data();
|
||||
#endif
|
||||
verStr.append( " on ").append(Utility::platformName());
|
||||
qDebug() << verStr;
|
||||
|
||||
fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet
|
||||
|
||||
@@ -868,6 +856,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
bool walkOk = true;
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
_renamedFolders.clear();
|
||||
|
||||
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
||||
qDebug() << "Error in local treewalk.";
|
||||
@@ -918,16 +907,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto databaseFingerprint = _journal->dataFingerprint();
|
||||
// If databaseFingerprint is null, this means that there was no information in the database
|
||||
// (for example, upgrading from a previous version, or first sync)
|
||||
// Note that an empty ("") fingerprint is valid and means it was empty on the server before.
|
||||
if (!databaseFingerprint.isNull()
|
||||
&& _discoveryMainThread->_dataFingerprint != databaseFingerprint) {
|
||||
qDebug() << "data fingerprint changed, assume restore from backup" << databaseFingerprint << _discoveryMainThread->_dataFingerprint;
|
||||
restoreOldFiles();
|
||||
} else if (!_hasForwardInTimeFiles && _backInTimeFiles >= 2) {
|
||||
if (!_hasForwardInTimeFiles && _backInTimeFiles >= 2) {
|
||||
qDebug() << "All the changes are bringing files in the past, asking the user";
|
||||
// this typically happen when a backup is restored on the server
|
||||
bool restore = false;
|
||||
@@ -970,9 +950,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_propagator.data(), SIGNAL(progress(const SyncFileItem &,quint64)),
|
||||
this, SLOT(slotProgress(const SyncFileItem &,quint64)));
|
||||
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
|
||||
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()), Qt::QueuedConnection);
|
||||
connect(_propagator.data(), SIGNAL(seenLockedFile(QString)), SIGNAL(seenLockedFile(QString)));
|
||||
connect(_propagator.data(), SIGNAL(touchedFile(QString)), SLOT(slotAddTouchedFile(QString)));
|
||||
|
||||
// apply the network limits to the propagator
|
||||
setNetworkLimits(_uploadLimit, _downloadLimit);
|
||||
@@ -1038,14 +1017,10 @@ void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob
|
||||
emit itemCompleted(item, job);
|
||||
}
|
||||
|
||||
void SyncEngine::slotFinished(bool success)
|
||||
void SyncEngine::slotFinished()
|
||||
{
|
||||
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
|
||||
|
||||
if (success) {
|
||||
_journal->setDataFingerprint(_discoveryMainThread->_dataFingerprint);
|
||||
}
|
||||
|
||||
// emit the treewalk results.
|
||||
if( ! _journal->postSyncCleanup( _seenFiles, _temporarilyUnavailablePaths ) ) {
|
||||
qDebug() << "Cleaning of synced ";
|
||||
@@ -1053,7 +1028,7 @@ void SyncEngine::slotFinished(bool success)
|
||||
|
||||
_journal->commit("All Finished.", false);
|
||||
emit treeWalkResult(_syncedItems);
|
||||
finalize(success);
|
||||
finalize(true); // FIXME: should it be true if there was errors?
|
||||
}
|
||||
|
||||
void SyncEngine::finalize(bool success)
|
||||
@@ -1073,8 +1048,6 @@ void SyncEngine::finalize(bool success)
|
||||
|
||||
// Delete the propagator only after emitting the signal.
|
||||
_propagator.clear();
|
||||
|
||||
_clearTouchedFilesTimer.start();
|
||||
}
|
||||
|
||||
void SyncEngine::slotProgress(const SyncFileItem& item, quint64 current)
|
||||
@@ -1179,8 +1152,9 @@ void SyncEngine::checkForPermission()
|
||||
if (perms.isNull()) {
|
||||
// No permissions set
|
||||
break;
|
||||
} if (!perms.contains("W")) {
|
||||
} if (!(*it)->_isDirectory && !perms.contains("W")) {
|
||||
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
|
||||
(*it)->_should_update_metadata = true;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
(*it)->_direction = SyncFileItem::Down;
|
||||
(*it)->_isRestoration = true;
|
||||
@@ -1202,6 +1176,7 @@ void SyncEngine::checkForPermission()
|
||||
}
|
||||
if (!perms.contains("D")) {
|
||||
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
|
||||
(*it)->_should_update_metadata = true;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
(*it)->_direction = SyncFileItem::Down;
|
||||
(*it)->_isRestoration = true;
|
||||
@@ -1220,6 +1195,7 @@ void SyncEngine::checkForPermission()
|
||||
}
|
||||
|
||||
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
|
||||
(*it)->_should_update_metadata = true;
|
||||
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
(*it)->_direction = SyncFileItem::Down;
|
||||
@@ -1368,6 +1344,7 @@ void SyncEngine::restoreOldFiles()
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
qDebug() << "restoreOldFiles: RESTORING" << (*it)->_file;
|
||||
(*it)->_should_update_metadata = true;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||
(*it)->_direction = SyncFileItem::Up;
|
||||
break;
|
||||
@@ -1382,28 +1359,24 @@ void SyncEngine::restoreOldFiles()
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::slotAddTouchedFile(const QString& fn)
|
||||
SyncFileItem* SyncEngine::findSyncItem(const QString &fileName) const
|
||||
{
|
||||
QString file = QDir::cleanPath(fn);
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
_touchedFiles.insert(file, timer);
|
||||
}
|
||||
|
||||
void SyncEngine::slotClearTouchedFiles()
|
||||
{
|
||||
_touchedFiles.clear();
|
||||
Q_FOREACH(const SyncFileItemPtr &item, _syncedItems) {
|
||||
// Directories will appear in this list as well, and will get their status set once all children have been propagated
|
||||
if ((item->_file == fileName || (!item->_renameTarget.isEmpty() && item->_renameTarget == fileName)))
|
||||
return item.data();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 SyncEngine::timeSinceFileTouched(const QString& fn) const
|
||||
{
|
||||
if (! _touchedFiles.contains(fn)) {
|
||||
return -1;
|
||||
// This copy is essential for thread safety.
|
||||
QSharedPointer<OwncloudPropagator> prop = _propagator;
|
||||
if (prop) {
|
||||
return prop->timeSinceFileTouched(fn);
|
||||
}
|
||||
|
||||
return _touchedFiles[fn].elapsed();
|
||||
return -1;
|
||||
}
|
||||
|
||||
AccountPtr SyncEngine::account() const
|
||||
|
||||
@@ -85,6 +85,8 @@ public:
|
||||
/* Return true if we detected that another sync is needed to complete the sync */
|
||||
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
|
||||
|
||||
SyncFileItem* findSyncItem(const QString &fileName) const;
|
||||
|
||||
/** Get the ms since a file was touched, or -1 if it wasn't.
|
||||
*
|
||||
* Thread-safe.
|
||||
@@ -150,17 +152,11 @@ signals:
|
||||
private slots:
|
||||
void slotRootEtagReceived(const QString &);
|
||||
void slotItemCompleted(const SyncFileItem& item, const PropagatorJob & job);
|
||||
void slotFinished(bool success);
|
||||
void slotFinished();
|
||||
void slotProgress(const SyncFileItem& item, quint64 curent);
|
||||
void slotDiscoveryJobFinished(int updateResult);
|
||||
void slotCleanPollsJobAborted(const QString &error);
|
||||
|
||||
/** Records that a file was touched by a job. */
|
||||
void slotAddTouchedFile(const QString& fn);
|
||||
|
||||
/** Wipes the _touchedFiles hash */
|
||||
void slotClearTouchedFiles();
|
||||
|
||||
private:
|
||||
void handleSyncError(CSYNC *ctx, const char *state);
|
||||
|
||||
@@ -260,12 +256,6 @@ private:
|
||||
CSyncChecksumHook _checksum_hook;
|
||||
|
||||
bool _anotherSyncNeeded;
|
||||
|
||||
/** Stores the time since a job touched a file. */
|
||||
QHash<QString, QElapsedTimer> _touchedFiles;
|
||||
|
||||
/** For clearing the _touchedFiles variable after sync finished */
|
||||
QTimer _clearTouchedFilesTimer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
|
||||
_serverHasIgnoredFiles(false), _hasBlacklistEntry(false),
|
||||
_errorMayBeBlacklisted(false), _status(NoStatus),
|
||||
_isRestoration(false),
|
||||
_isRestoration(false), _should_update_metadata(false),
|
||||
_httpErrorCode(0), _requestDuration(0), _affectedItems(1),
|
||||
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0), _size(0), _inode(0)
|
||||
{
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
// Variables useful to report to the user
|
||||
Status _status BITFIELD(4);
|
||||
bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
|
||||
bool _should_update_metadata BITFIELD(1);
|
||||
quint16 _httpErrorCode;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
QByteArray _responseTimeStamp;
|
||||
|
||||
@@ -32,7 +32,7 @@ void SyncFileStatus::set(SyncFileStatusTag tag)
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
SyncFileStatus::SyncFileStatusTag SyncFileStatus::tag() const
|
||||
SyncFileStatus::SyncFileStatusTag SyncFileStatus::tag()
|
||||
{
|
||||
return _tag;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ void SyncFileStatus::setSharedWithMe(bool isShared)
|
||||
_sharedWithMe = isShared;
|
||||
}
|
||||
|
||||
bool SyncFileStatus::sharedWithMe() const
|
||||
bool SyncFileStatus::sharedWithMe()
|
||||
{
|
||||
return _sharedWithMe;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#ifndef SYNCFILESTATUS_H
|
||||
#define SYNCFILESTATUS_H
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "owncloudlib.h"
|
||||
@@ -41,10 +39,10 @@ public:
|
||||
SyncFileStatus(SyncFileStatusTag);
|
||||
|
||||
void set(SyncFileStatusTag tag);
|
||||
SyncFileStatusTag tag() const;
|
||||
SyncFileStatusTag tag();
|
||||
|
||||
void setSharedWithMe( bool isShared );
|
||||
bool sharedWithMe() const;
|
||||
bool sharedWithMe();
|
||||
|
||||
QString toSocketAPIString() const;
|
||||
private:
|
||||
@@ -52,16 +50,6 @@ private:
|
||||
bool _sharedWithMe;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator==(const SyncFileStatus &a, const SyncFileStatus &b) {
|
||||
return a.tag() == b.tag() && a.sharedWithMe() == b.sharedWithMe();
|
||||
}
|
||||
|
||||
inline bool operator!=(const SyncFileStatus &a, const SyncFileStatus &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SyncFileStatus)
|
||||
|
||||
#endif // SYNCFILESTATUS_H
|
||||
|
||||
@@ -56,8 +56,7 @@ static SyncFileStatus::SyncFileStatusTag lookupProblem(const QString &pathToMatc
|
||||
static inline bool showErrorInSocketApi(const SyncFileItem& item)
|
||||
{
|
||||
const auto status = item._status;
|
||||
return item._instruction == CSYNC_INSTRUCTION_ERROR
|
||||
|| status == SyncFileItem::NormalError
|
||||
return status == SyncFileItem::NormalError
|
||||
|| status == SyncFileItem::FatalError
|
||||
|| item._hasBlacklistEntry;
|
||||
}
|
||||
@@ -65,8 +64,7 @@ static inline bool showErrorInSocketApi(const SyncFileItem& item)
|
||||
static inline bool showWarningInSocketApi(const SyncFileItem& item)
|
||||
{
|
||||
const auto status = item._status;
|
||||
return item._instruction == CSYNC_INSTRUCTION_IGNORE
|
||||
|| status == SyncFileItem::FileIgnored
|
||||
return status == SyncFileItem::FileIgnored
|
||||
|| status == SyncFileItem::Conflict
|
||||
|| status == SyncFileItem::Restoration;
|
||||
}
|
||||
@@ -78,18 +76,30 @@ SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
||||
SLOT(slotAboutToPropagate(SyncFileItemVector&)));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItem&, const PropagatorJob&)),
|
||||
SLOT(slotItemCompleted(const SyncFileItem&)));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncFinished()));
|
||||
connect(syncEngine, SIGNAL(started()), SLOT(slotSyncEngineRunningChanged()));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncEngineRunningChanged()));
|
||||
}
|
||||
|
||||
SyncFileItem SyncFileStatusTracker::rootSyncFileItem()
|
||||
{
|
||||
SyncFileItem fakeRootItem;
|
||||
// It's is not entirely correct to use the sync's status as we'll show the root folder as
|
||||
// syncing even though no child might end up being propagated, but will give us something
|
||||
// better than always UpToDate for now.
|
||||
fakeRootItem._status = _syncEngine->isSyncRunning() ? SyncFileItem::NoStatus : SyncFileItem::Success;
|
||||
fakeRootItem._isDirectory = true;
|
||||
return fakeRootItem;
|
||||
}
|
||||
|
||||
SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
||||
{
|
||||
Q_ASSERT(!relativePath.endsWith(QLatin1Char('/')));
|
||||
// normalization is required for OS X to match file names properly
|
||||
QString normalizedRelativePath = relativePath.normalized(QString::NormalizationForm_C);
|
||||
Q_ASSERT(!normalizedRelativePath.endsWith(QLatin1Char('/')));
|
||||
|
||||
if (relativePath.isEmpty()) {
|
||||
// This is the root sync folder, it doesn't have an entry in the database and won't be walked by csync, so resolve manually.
|
||||
return resolveSyncAndErrorStatus(QString(), NotShared);
|
||||
if (normalizedRelativePath.isEmpty()) {
|
||||
// This is the root sync folder, it doesn't have an entry in the database and won't be walked by csync, so create one manually.
|
||||
return syncFileItemStatus(rootSyncFileItem());
|
||||
}
|
||||
|
||||
// The SyncEngine won't notify us at all for CSYNC_FILE_SILENTLY_EXCLUDED
|
||||
@@ -98,23 +108,27 @@ SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
||||
// update the exclude list at runtime and doing it statically here removes
|
||||
// our ability to notify changes through the fileStatusChanged signal,
|
||||
// it's an acceptable compromize to treat all exclude types the same.
|
||||
if( _syncEngine->excludedFiles().isExcluded(_syncEngine->localPath() + relativePath,
|
||||
if( _syncEngine->excludedFiles().isExcluded(_syncEngine->localPath() + normalizedRelativePath,
|
||||
_syncEngine->localPath(),
|
||||
_syncEngine->ignoreHiddenFiles()) ) {
|
||||
return SyncFileStatus(SyncFileStatus::StatusWarning);
|
||||
}
|
||||
|
||||
if ( _dirtyPaths.contains(relativePath) )
|
||||
if ( _dirtyPaths.contains(normalizedRelativePath) )
|
||||
return SyncFileStatus::StatusSync;
|
||||
|
||||
// First look it up in the database to know if it's shared
|
||||
SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(relativePath);
|
||||
if (rec.isValid()) {
|
||||
return resolveSyncAndErrorStatus(relativePath, rec._remotePerm.contains("S") ? Shared : NotShared);
|
||||
SyncFileItem* item = _syncEngine->findSyncItem(normalizedRelativePath);
|
||||
if (item) {
|
||||
return syncFileItemStatus(*item);
|
||||
}
|
||||
|
||||
// Must be a new file not yet in the database, check if it's syncing or has an error.
|
||||
return resolveSyncAndErrorStatus(relativePath, NotShared, PathUnknown);
|
||||
// If we're not currently syncing that file, look it up in the database to know if it's shared
|
||||
SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(normalizedRelativePath);
|
||||
if (rec.isValid()) {
|
||||
return syncFileItemStatus(rec.toSyncFileItem());
|
||||
}
|
||||
// Must be a new file, wait for the filesystem watcher to trigger a sync
|
||||
return SyncFileStatus();
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotPathTouched(const QString& fileName)
|
||||
@@ -128,74 +142,21 @@ void SyncFileStatusTracker::slotPathTouched(const QString& fileName)
|
||||
emit fileStatusChanged(fileName, SyncFileStatus::StatusSync);
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::incSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange)
|
||||
{
|
||||
// Will return 0 (and increase to 1) if the path wasn't in the map yet
|
||||
int count = _syncCount[relativePath]++;
|
||||
if (!count) {
|
||||
if (emitStatusChange)
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), fileStatus(relativePath));
|
||||
|
||||
// We passed from OK to SYNC, increment the parent to keep it marked as
|
||||
// SYNC while we propagate ourselves and our own children.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
incSyncCount(relativePath.left(lastSlashIndex), EmitStatusChange);
|
||||
else if (!relativePath.isEmpty())
|
||||
incSyncCount(QString(), EmitStatusChange);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::decSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange)
|
||||
{
|
||||
int count = --_syncCount[relativePath];
|
||||
if (!count) {
|
||||
// Remove from the map, same as 0
|
||||
_syncCount.remove(relativePath);
|
||||
|
||||
if (emitStatusChange)
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), fileStatus(relativePath));
|
||||
|
||||
// We passed from SYNC to OK, decrement our parent.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
decSyncCount(relativePath.left(lastSlashIndex), EmitStatusChange);
|
||||
else if (!relativePath.isEmpty())
|
||||
decSyncCount(QString(), EmitStatusChange);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
{
|
||||
Q_ASSERT(_syncCount.isEmpty());
|
||||
|
||||
std::map<QString, SyncFileStatus::SyncFileStatusTag> oldProblems;
|
||||
std::swap(_syncProblems, oldProblems);
|
||||
|
||||
foreach (const SyncFileItemPtr &item, items) {
|
||||
// qDebug() << Q_FUNC_INFO << "Investigating" << item->destination() << item->_status << item->_instruction;
|
||||
// qDebug() << Q_FUNC_INFO << "Investigating" << item->destination() << item->_status;
|
||||
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusError;
|
||||
invalidateParentPaths(item->destination());
|
||||
} else if (showWarningInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusWarning;
|
||||
}
|
||||
|
||||
// Mark this path as syncing for instructions that will result in propagation,
|
||||
// but DontEmitStatusChange since we're going to emit for ourselves using the
|
||||
// info in the SyncFileItem we received, parents will still be emit if needed.
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
incSyncCount(item->destination(), DontEmitStatusChange);
|
||||
}
|
||||
|
||||
_dirtyPaths.remove(item->destination());
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), resolveSyncAndErrorStatus(item->destination(), item->_remotePerm.contains("S") ? Shared : NotShared));
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), syncFileItemStatus(*item));
|
||||
}
|
||||
|
||||
// Some metadata status won't trigger files to be synced, make sure that we
|
||||
@@ -203,7 +164,7 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
// Swap into a copy since fileStatus() reads _dirtyPaths to determine the status
|
||||
QSet<QString> oldDirtyPaths;
|
||||
std::swap(_dirtyPaths, oldDirtyPaths);
|
||||
for (auto it = oldDirtyPaths.constBegin(); it != oldDirtyPaths.constEnd(); ++it)
|
||||
for (auto it = oldDirtyPaths.begin(); it != oldDirtyPaths.end(); ++it)
|
||||
emit fileStatusChanged(getSystemDestination(*it), fileStatus(*it));
|
||||
|
||||
// Make sure to push any status that might have been resolved indirectly since the last sync
|
||||
@@ -221,7 +182,7 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item)
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << item.destination() << item._status << item._instruction;
|
||||
// qDebug() << Q_FUNC_INFO << item.destination() << item._status;
|
||||
|
||||
if (showErrorInSocketApi(item)) {
|
||||
_syncProblems[item._file] = SyncFileStatus::StatusError;
|
||||
@@ -232,46 +193,37 @@ void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item)
|
||||
_syncProblems.erase(item._file);
|
||||
}
|
||||
|
||||
// decSyncCount calls *must* be symetric with incSyncCount calls in slotAboutToPropagate
|
||||
if (item._instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item._instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
decSyncCount(item.destination(), DontEmitStatusChange);
|
||||
}
|
||||
emit fileStatusChanged(getSystemDestination(item.destination()), resolveSyncAndErrorStatus(item.destination(), item._remotePerm.contains("S") ? Shared : NotShared));
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotSyncFinished()
|
||||
{
|
||||
// Clear the sync counts to reduce the impact of unsymetrical inc/dec calls (e.g. when directory job abort)
|
||||
QHash<QString, int> oldSyncCount;
|
||||
std::swap(_syncCount, oldSyncCount);
|
||||
for (auto it = oldSyncCount.begin(); it != oldSyncCount.end(); ++it)
|
||||
emit fileStatusChanged(getSystemDestination(it.key()), fileStatus(it.key()));
|
||||
emit fileStatusChanged(getSystemDestination(item.destination()), syncFileItemStatus(item));
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotSyncEngineRunningChanged()
|
||||
{
|
||||
emit fileStatusChanged(_syncEngine->localPath(), resolveSyncAndErrorStatus(QString(), NotShared));
|
||||
emit fileStatusChanged(_syncEngine->localPath(), syncFileItemStatus(rootSyncFileItem()));
|
||||
}
|
||||
|
||||
SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag isShared, PathKnownFlag isPathKnown)
|
||||
SyncFileStatus SyncFileStatusTracker::syncFileItemStatus(const SyncFileItem& item)
|
||||
{
|
||||
// If it's a new file and that we're not syncing it yet,
|
||||
// don't show any icon and wait for the filesystem watcher to trigger a sync.
|
||||
SyncFileStatus status(isPathKnown ? SyncFileStatus::StatusUpToDate : SyncFileStatus::StatusNone);
|
||||
if (_syncCount.value(relativePath)) {
|
||||
// Hack to know if the item was taken from the sync engine (Sync), or from the database (UpToDate)
|
||||
// Mark any directory in the SyncEngine's items as syncing, this is currently how we mark parent directories
|
||||
// of currently syncing items since the PropagateDirectory job will mark the directorie's SyncFileItem::_status as Success
|
||||
// once all child jobs have been completed.
|
||||
bool waitingForPropagation = (item._isDirectory || item._direction != SyncFileItem::None) && item._status == SyncFileItem::NoStatus;
|
||||
SyncFileStatus status(SyncFileStatus::StatusUpToDate);
|
||||
if (waitingForPropagation) {
|
||||
status.set(SyncFileStatus::StatusSync);
|
||||
} else if (showErrorInSocketApi(item)) {
|
||||
status.set(SyncFileStatus::StatusError);
|
||||
} else if (showWarningInSocketApi(item)) {
|
||||
status.set(SyncFileStatus::StatusWarning);
|
||||
} else {
|
||||
// After a sync finished, we need to show the users issues from that last sync like the activity list does.
|
||||
// Also used for parent directories showing a warning for an error child.
|
||||
SyncFileStatus::SyncFileStatusTag problemStatus = lookupProblem(relativePath, _syncProblems);
|
||||
SyncFileStatus::SyncFileStatusTag problemStatus = lookupProblem(item.destination(), _syncProblems);
|
||||
if (problemStatus != SyncFileStatus::StatusNone)
|
||||
status.set(problemStatus);
|
||||
}
|
||||
|
||||
if (isShared)
|
||||
if (item._remotePerm.contains("S"))
|
||||
status.setSharedWithMe(true);
|
||||
|
||||
return status;
|
||||
|
||||
@@ -46,25 +46,19 @@ signals:
|
||||
private slots:
|
||||
void slotAboutToPropagate(SyncFileItemVector& items);
|
||||
void slotItemCompleted(const SyncFileItem& item);
|
||||
void slotSyncFinished();
|
||||
void slotSyncEngineRunningChanged();
|
||||
|
||||
private:
|
||||
enum SharedFlag { NotShared = 0, Shared };
|
||||
enum PathKnownFlag { PathUnknown = 0, PathKnown };
|
||||
enum EmitStatusChangeFlag { DontEmitStatusChange = 0, EmitStatusChange };
|
||||
SyncFileStatus resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag isShared, PathKnownFlag isPathKnown = PathKnown);
|
||||
SyncFileStatus syncFileItemStatus(const SyncFileItem& item);
|
||||
SyncFileItem rootSyncFileItem();
|
||||
|
||||
void invalidateParentPaths(const QString& path);
|
||||
QString getSystemDestination(const QString& relativePath);
|
||||
void incSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange);
|
||||
void decSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange);
|
||||
|
||||
SyncEngine* _syncEngine;
|
||||
|
||||
std::map<QString, SyncFileStatus::SyncFileStatusTag> _syncProblems;
|
||||
QSet<QString> _dirtyPaths;
|
||||
QHash<QString, int> _syncCount;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -286,13 +286,6 @@ bool SyncJournalDb::checkConnect()
|
||||
return sqlFail("Create table version", createQuery);
|
||||
}
|
||||
|
||||
// create the checksumtype table.
|
||||
createQuery.prepare("CREATE TABLE IF NOT EXISTS datafingerprint("
|
||||
"fingerprint TEXT UNIQUE"
|
||||
");");
|
||||
if (!createQuery.exec()) {
|
||||
return sqlFail("Create table datafingerprint", createQuery);
|
||||
}
|
||||
|
||||
createQuery.prepare("CREATE TABLE IF NOT EXISTS version("
|
||||
"major INTEGER(8),"
|
||||
@@ -385,12 +378,6 @@ bool SyncJournalDb::checkConnect()
|
||||
" SET contentChecksum = ?2, contentChecksumTypeId = ?3"
|
||||
" WHERE phash == ?1;");
|
||||
|
||||
_setFileRecordLocalMetadataQuery.reset(new SqlQuery(_db));
|
||||
_setFileRecordLocalMetadataQuery->prepare(
|
||||
"UPDATE metadata"
|
||||
" SET inode=?2, modtime=?3, filesize=?4"
|
||||
" WHERE phash == ?1;");
|
||||
|
||||
_getDownloadInfoQuery.reset(new SqlQuery(_db) );
|
||||
_getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM "
|
||||
"downloadinfo WHERE path=?1" );
|
||||
@@ -449,14 +436,6 @@ bool SyncJournalDb::checkConnect()
|
||||
_insertChecksumTypeQuery.reset(new SqlQuery(_db));
|
||||
_insertChecksumTypeQuery->prepare("INSERT OR IGNORE INTO checksumtype (name) VALUES (?1)");
|
||||
|
||||
_getDataFingerprintQuery.reset(new SqlQuery(_db));
|
||||
_getDataFingerprintQuery->prepare("SELECT fingerprint FROM datafingerprint");
|
||||
|
||||
_setDataFingerprintQuery1.reset(new SqlQuery(_db));
|
||||
_setDataFingerprintQuery1->prepare("DELETE FROM datafingerprint;");
|
||||
_setDataFingerprintQuery2.reset(new SqlQuery(_db));
|
||||
_setDataFingerprintQuery2->prepare("INSERT INTO datafingerprint (fingerprint) VALUES (?1);");
|
||||
|
||||
// don't start a new transaction now
|
||||
commitInternal(QString("checkConnect End"), false);
|
||||
|
||||
@@ -479,7 +458,6 @@ void SyncJournalDb::close()
|
||||
_getFileRecordQuery.reset(0);
|
||||
_setFileRecordQuery.reset(0);
|
||||
_setFileRecordChecksumQuery.reset(0);
|
||||
_setFileRecordLocalMetadataQuery.reset(0);
|
||||
_getDownloadInfoQuery.reset(0);
|
||||
_setDownloadInfoQuery.reset(0);
|
||||
_deleteDownloadInfoQuery.reset(0);
|
||||
@@ -494,9 +472,6 @@ void SyncJournalDb::close()
|
||||
_getChecksumTypeIdQuery.reset(0);
|
||||
_getChecksumTypeQuery.reset(0);
|
||||
_insertChecksumTypeQuery.reset(0);
|
||||
_getDataFingerprintQuery.reset(0);
|
||||
_setDataFingerprintQuery1.reset(0);
|
||||
_setDataFingerprintQuery2.reset(0);
|
||||
|
||||
_db.close();
|
||||
_avoidReadFromDbOnNextSyncFilter.clear();
|
||||
@@ -971,40 +946,6 @@ bool SyncJournalDb::updateFileRecordChecksum(const QString& filename,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::updateLocalMetadata(const QString& filename,
|
||||
qint64 modtime, quint64 size, quint64 inode)
|
||||
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
qlonglong phash = getPHash(filename);
|
||||
if( !checkConnect() ) {
|
||||
qDebug() << "Failed to connect database.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto & query = _setFileRecordLocalMetadataQuery;
|
||||
|
||||
query->reset_and_clear_bindings();
|
||||
query->bindValue(1, QString::number(phash));
|
||||
query->bindValue(2, inode);
|
||||
query->bindValue(3, modtime);
|
||||
query->bindValue(4, size);
|
||||
|
||||
if( !query->exec() ) {
|
||||
qWarning() << "Error SQL statement updateLocalMetadata: "
|
||||
<< query->lastQuery() << " :"
|
||||
<< query->error();
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << query->lastQuery() << phash << inode
|
||||
<< modtime << size;
|
||||
|
||||
query->reset_and_clear_bindings();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::setFileRecordMetadata(const SyncJournalFileRecord& record)
|
||||
{
|
||||
SyncJournalFileRecord existing = getFileRecord(record._path);
|
||||
@@ -1661,49 +1602,6 @@ int SyncJournalDb::mapChecksumType(const QByteArray& checksumType)
|
||||
return _getChecksumTypeIdQuery->intValue(0);
|
||||
}
|
||||
|
||||
QByteArray SyncJournalDb::dataFingerprint()
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
if (!checkConnect()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
_getDataFingerprintQuery->reset_and_clear_bindings();
|
||||
if (!_getDataFingerprintQuery->exec()) {
|
||||
qWarning() << "Error SQL statement dataFingerprint: "
|
||||
<< _getDataFingerprintQuery->lastQuery() << " :"
|
||||
<< _getDataFingerprintQuery->error();
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (!_getDataFingerprintQuery->next()) {
|
||||
return QByteArray();
|
||||
}
|
||||
return _getDataFingerprintQuery->baValue(0);
|
||||
}
|
||||
|
||||
void SyncJournalDb::setDataFingerprint(const QByteArray &dataFingerprint)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
if (!checkConnect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_setDataFingerprintQuery1->reset_and_clear_bindings();
|
||||
if (!_setDataFingerprintQuery1->exec()) {
|
||||
qWarning() << "Error SQL statement setDataFingerprint1: "
|
||||
<< _setDataFingerprintQuery1->lastQuery() << " :"
|
||||
<< _setDataFingerprintQuery1->error();
|
||||
}
|
||||
|
||||
_setDataFingerprintQuery2->reset_and_clear_bindings();
|
||||
_setDataFingerprintQuery2->bindValue(1, dataFingerprint);
|
||||
if (!_setDataFingerprintQuery2->exec()) {
|
||||
qWarning() << "Error SQL statement setDataFingerprint2: "
|
||||
<< _setDataFingerprintQuery2->lastQuery() << " :"
|
||||
<< _setDataFingerprintQuery2->error();
|
||||
}
|
||||
}
|
||||
|
||||
void SyncJournalDb::commit(const QString& context, bool startTrans)
|
||||
{
|
||||
|
||||
@@ -52,8 +52,6 @@ public:
|
||||
bool updateFileRecordChecksum(const QString& filename,
|
||||
const QByteArray& contentChecksum,
|
||||
const QByteArray& contentChecksumType);
|
||||
bool updateLocalMetadata(const QString& filename,
|
||||
qint64 modtime, quint64 size, quint64 inode);
|
||||
bool exists();
|
||||
void walCheckpoint();
|
||||
|
||||
@@ -156,12 +154,6 @@ public:
|
||||
*/
|
||||
QByteArray getChecksumType(int checksumTypeId);
|
||||
|
||||
/**
|
||||
* The data-fingerprint used to detect backup
|
||||
*/
|
||||
void setDataFingerprint(const QByteArray &dataFingerprint);
|
||||
QByteArray dataFingerprint();
|
||||
|
||||
private:
|
||||
bool updateDatabaseStructure();
|
||||
bool updateMetadataTableStructure();
|
||||
@@ -190,7 +182,6 @@ private:
|
||||
QScopedPointer<SqlQuery> _getFileRecordQuery;
|
||||
QScopedPointer<SqlQuery> _setFileRecordQuery;
|
||||
QScopedPointer<SqlQuery> _setFileRecordChecksumQuery;
|
||||
QScopedPointer<SqlQuery> _setFileRecordLocalMetadataQuery;
|
||||
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
|
||||
QScopedPointer<SqlQuery> _setDownloadInfoQuery;
|
||||
QScopedPointer<SqlQuery> _deleteDownloadInfoQuery;
|
||||
@@ -205,9 +196,6 @@ private:
|
||||
QScopedPointer<SqlQuery> _getChecksumTypeIdQuery;
|
||||
QScopedPointer<SqlQuery> _getChecksumTypeQuery;
|
||||
QScopedPointer<SqlQuery> _insertChecksumTypeQuery;
|
||||
QScopedPointer<SqlQuery> _getDataFingerprintQuery;
|
||||
QScopedPointer<SqlQuery> _setDataFingerprintQuery1;
|
||||
QScopedPointer<SqlQuery> _setDataFingerprintQuery2;
|
||||
|
||||
/* This is the list of paths we called avoidReadFromDbOnNextSync on.
|
||||
* It means that they should not be written to the DB in any case since doing
|
||||
|
||||
@@ -35,13 +35,6 @@
|
||||
#else
|
||||
#include <QStandardPaths>
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
||||
#include <QCollator>
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
#include <QSysInfo>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/statvfs.h>
|
||||
@@ -427,25 +420,6 @@ bool Utility::isBSD()
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Utility::platformName()
|
||||
{
|
||||
QString re("Windows");
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
|
||||
if( isMac() ) {
|
||||
re = QLatin1String("MacOSX");
|
||||
} else if( isLinux() ) {
|
||||
re = QLatin1String("Linux");
|
||||
} else if( isBSD() ) {
|
||||
re = QLatin1String("BSD");
|
||||
} else if( isUnix() ) {
|
||||
re = QLatin1String("Unix");
|
||||
}
|
||||
#else
|
||||
re = QSysInfo::prettyProductName();
|
||||
#endif
|
||||
return re;
|
||||
}
|
||||
|
||||
void Utility::crash()
|
||||
{
|
||||
@@ -572,18 +546,4 @@ quint64 Utility::StopWatch::durationOfLap( const QString& lapName ) const
|
||||
return _lapTimes.value(lapName, 0);
|
||||
}
|
||||
|
||||
void Utility::sortFilenames(QStringList& fileNames)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
||||
QCollator collator;
|
||||
collator.setNumericMode(true);
|
||||
collator.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
qSort(fileNames.begin(), fileNames.end(), collator);
|
||||
#elif QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
fileNames.sort(Qt::CaseInsensitive);
|
||||
#else
|
||||
fileNames.sort();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -91,7 +91,6 @@ namespace Utility
|
||||
OWNCLOUDSYNC_EXPORT bool isLinux(); // use with care
|
||||
OWNCLOUDSYNC_EXPORT bool isBSD(); // use with care, does not match OS X
|
||||
|
||||
OWNCLOUDSYNC_EXPORT QString platformName();
|
||||
// crash helper for --debug
|
||||
OWNCLOUDSYNC_EXPORT void crash();
|
||||
|
||||
@@ -137,11 +136,6 @@ namespace Utility
|
||||
quint64 durationOfLap( const QString& lapName ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sort a QStringList in a way that's appropriate for filenames
|
||||
*/
|
||||
OWNCLOUDSYNC_EXPORT void sortFilenames(QStringList& fileNames);
|
||||
|
||||
}
|
||||
/** @} */ // \addtogroup
|
||||
|
||||
|
||||
@@ -42,10 +42,6 @@ owncloud_add_test(FileSystem "")
|
||||
owncloud_add_test(ChecksumValidator "")
|
||||
|
||||
owncloud_add_test(ExcludedFiles "")
|
||||
if(HAVE_QT5 AND NOT BUILD_WITH_QT4)
|
||||
owncloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
endif(HAVE_QT5 AND NOT BUILD_WITH_QT4)
|
||||
|
||||
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
||||
list(APPEND FolderMan_SRC ../src/gui/folder.cpp )
|
||||
|
||||
@@ -1,693 +0,0 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "account.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "filesystem.h"
|
||||
#include "syncengine.h"
|
||||
#include "syncjournaldb.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QNetworkReply>
|
||||
#include <QtTest>
|
||||
|
||||
static const QUrl sRootUrl("owncloud://somehost/owncloud/remote.php/webdav/");
|
||||
|
||||
namespace {
|
||||
QString generateEtag() {
|
||||
return QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch(), 16);
|
||||
}
|
||||
|
||||
class PathComponents : public QStringList {
|
||||
public:
|
||||
PathComponents(const QString &path) : QStringList{path.split('/', QString::SkipEmptyParts)} { }
|
||||
PathComponents(const QStringList &pathComponents) : QStringList{pathComponents} { }
|
||||
|
||||
PathComponents parentDirComponents() const {
|
||||
return PathComponents{mid(0, size() - 1)};
|
||||
}
|
||||
PathComponents subComponents() const { return PathComponents{mid(1)}; }
|
||||
QString pathRoot() const { return first(); }
|
||||
QString fileName() const { return last(); }
|
||||
};
|
||||
}
|
||||
|
||||
class FileModifier
|
||||
{
|
||||
public:
|
||||
virtual ~FileModifier() { }
|
||||
virtual void remove(const QString &relativePath) = 0;
|
||||
virtual void insert(const QString &relativePath, qint64 size = 64, char contentChar = 'W') = 0;
|
||||
virtual void setContents(const QString &relativePath, char contentChar) = 0;
|
||||
virtual void appendByte(const QString &relativePath) = 0;
|
||||
virtual void mkdir(const QString &relativePath) = 0;
|
||||
};
|
||||
|
||||
class DiskFileModifier : public FileModifier
|
||||
{
|
||||
QDir _rootDir;
|
||||
public:
|
||||
DiskFileModifier(const QString &rootDirPath) : _rootDir(rootDirPath) { }
|
||||
void remove(const QString &relativePath) override {
|
||||
QFileInfo fi{_rootDir.filePath(relativePath)};
|
||||
if (fi.isFile())
|
||||
QVERIFY(_rootDir.remove(relativePath));
|
||||
else
|
||||
QVERIFY(QDir{fi.filePath()}.removeRecursively());
|
||||
}
|
||||
void insert(const QString &relativePath, qint64 size = 64, char contentChar = 'W') override {
|
||||
QFile file{_rootDir.filePath(relativePath)};
|
||||
QVERIFY(!file.exists());
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(QByteArray{}.fill(contentChar, size));
|
||||
file.close();
|
||||
// Set the mtime 30 seconds in the past, for some tests that need to make sure that the mtime differs.
|
||||
OCC::FileSystem::setModTime(file.fileName(), OCC::Utility::qDateTimeToTime_t(QDateTime::currentDateTime().addSecs(-30)));
|
||||
}
|
||||
void setContents(const QString &relativePath, char contentChar) override {
|
||||
QFile file{_rootDir.filePath(relativePath)};
|
||||
QVERIFY(file.exists());
|
||||
qint64 size = file.size();
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(QByteArray{}.fill(contentChar, size));
|
||||
}
|
||||
void appendByte(const QString &relativePath) override {
|
||||
QFile file{_rootDir.filePath(relativePath)};
|
||||
QVERIFY(file.exists());
|
||||
file.open(QFile::ReadWrite);
|
||||
QByteArray contents = file.read(1);
|
||||
file.seek(file.size());
|
||||
file.write(contents);
|
||||
}
|
||||
void mkdir(const QString &relativePath) override {
|
||||
_rootDir.mkpath(relativePath);
|
||||
}
|
||||
};
|
||||
|
||||
class FileInfo : public FileModifier
|
||||
{
|
||||
public:
|
||||
static FileInfo A12_B12_C12_S12() {
|
||||
FileInfo fi{QString{}, {
|
||||
{QStringLiteral("A"), {
|
||||
{QStringLiteral("a1"), 4},
|
||||
{QStringLiteral("a2"), 4}
|
||||
}},
|
||||
{QStringLiteral("B"), {
|
||||
{QStringLiteral("b1"), 16},
|
||||
{QStringLiteral("b2"), 16}
|
||||
}},
|
||||
{QStringLiteral("C"), {
|
||||
{QStringLiteral("c1"), 24},
|
||||
{QStringLiteral("c2"), 24}
|
||||
}},
|
||||
}};
|
||||
FileInfo sharedFolder{QStringLiteral("S"), {
|
||||
{QStringLiteral("s1"), 32},
|
||||
{QStringLiteral("s2"), 32}
|
||||
}};
|
||||
sharedFolder.isShared = true;
|
||||
sharedFolder.children[QStringLiteral("s1")].isShared = true;
|
||||
sharedFolder.children[QStringLiteral("s2")].isShared = true;
|
||||
fi.children.insert(sharedFolder.name, std::move(sharedFolder));
|
||||
return fi;
|
||||
}
|
||||
|
||||
FileInfo() = default;
|
||||
FileInfo(const QString &name) : name{name} { }
|
||||
FileInfo(const QString &name, qint64 size) : name{name}, isDir{false}, size{size} { }
|
||||
FileInfo(const QString &name, qint64 size, char contentChar) : name{name}, isDir{false}, size{size}, contentChar{contentChar} { }
|
||||
FileInfo(const QString &name, const std::initializer_list<FileInfo> &children) : name{name} {
|
||||
QString p = path();
|
||||
for (const auto &source : children) {
|
||||
auto &dest = this->children[source.name] = source;
|
||||
dest.parentPath = p;
|
||||
}
|
||||
}
|
||||
|
||||
void remove(const QString &relativePath) override {
|
||||
const PathComponents pathComponents{relativePath};
|
||||
FileInfo *parent = findInvalidatingEtags(pathComponents.parentDirComponents());
|
||||
Q_ASSERT(parent);
|
||||
parent->children.erase(std::find_if(parent->children.begin(), parent->children.end(),
|
||||
[&pathComponents](const FileInfo &fi){ return fi.name == pathComponents.fileName(); }));
|
||||
}
|
||||
|
||||
void insert(const QString &relativePath, qint64 size = 64, char contentChar = 'W') override {
|
||||
create(relativePath, size, contentChar);
|
||||
}
|
||||
|
||||
void setContents(const QString &relativePath, char contentChar) override {
|
||||
FileInfo *file = findInvalidatingEtags(relativePath);
|
||||
Q_ASSERT(file);
|
||||
file->contentChar = contentChar;
|
||||
}
|
||||
|
||||
void appendByte(const QString &relativePath) override {
|
||||
FileInfo *file = findInvalidatingEtags(relativePath);
|
||||
Q_ASSERT(file);
|
||||
file->size += 1;
|
||||
}
|
||||
|
||||
void mkdir(const QString &relativePath) override {
|
||||
createDir(relativePath);
|
||||
}
|
||||
|
||||
FileInfo *find(const PathComponents &pathComponents, const bool invalidateEtags = false) {
|
||||
if (pathComponents.isEmpty()) {
|
||||
if (invalidateEtags)
|
||||
etag = generateEtag();
|
||||
return this;
|
||||
}
|
||||
QString childName = pathComponents.pathRoot();
|
||||
auto it = children.find(childName);
|
||||
if (it != children.end()) {
|
||||
auto file = it->find(pathComponents.subComponents(), invalidateEtags);
|
||||
if (file && invalidateEtags)
|
||||
// Update parents on the way back
|
||||
etag = file->etag;
|
||||
return file;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileInfo *createDir(const QString &relativePath) {
|
||||
const PathComponents pathComponents{relativePath};
|
||||
FileInfo *parent = findInvalidatingEtags(pathComponents.parentDirComponents());
|
||||
Q_ASSERT(parent);
|
||||
FileInfo &child = parent->children[pathComponents.fileName()] = FileInfo{pathComponents.fileName()};
|
||||
child.parentPath = parent->path();
|
||||
child.etag = generateEtag();
|
||||
return &child;
|
||||
}
|
||||
|
||||
FileInfo *create(const QString &relativePath, qint64 size, char contentChar) {
|
||||
const PathComponents pathComponents{relativePath};
|
||||
FileInfo *parent = findInvalidatingEtags(pathComponents.parentDirComponents());
|
||||
Q_ASSERT(parent);
|
||||
FileInfo &child = parent->children[pathComponents.fileName()] = FileInfo{pathComponents.fileName(), size};
|
||||
child.parentPath = parent->path();
|
||||
child.contentChar = contentChar;
|
||||
child.etag = generateEtag();
|
||||
return &child;
|
||||
}
|
||||
|
||||
bool operator<(const FileInfo &other) const {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
bool operator==(const FileInfo &other) const {
|
||||
// Consider files to be equal between local<->remote as a user would.
|
||||
return name == other.name
|
||||
&& isDir == other.isDir
|
||||
&& size == other.size
|
||||
&& contentChar == other.contentChar
|
||||
&& children == other.children;
|
||||
}
|
||||
|
||||
QString path() const {
|
||||
return (parentPath.isEmpty() ? QString() : (parentPath + '/')) + name;
|
||||
}
|
||||
|
||||
QString name;
|
||||
bool isDir = true;
|
||||
bool isShared = false;
|
||||
QDateTime lastModified = QDateTime::currentDateTime().addDays(-7);
|
||||
QString etag = generateEtag();
|
||||
qint64 size = 0;
|
||||
char contentChar = 'W';
|
||||
|
||||
// Sorted by name to be able to compare trees
|
||||
QMap<QString, FileInfo> children;
|
||||
QString parentPath;
|
||||
|
||||
private:
|
||||
FileInfo *findInvalidatingEtags(const PathComponents &pathComponents) {
|
||||
return find(pathComponents, true);
|
||||
}
|
||||
};
|
||||
|
||||
class FakePropfindReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QByteArray payload;
|
||||
|
||||
FakePropfindReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
// Don't care about the request and just return a full propfind
|
||||
const QString davUri{QStringLiteral("DAV:")};
|
||||
const QString ocUri{QStringLiteral("http://owncloud.org/ns")};
|
||||
QBuffer buffer{&payload};
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
QXmlStreamWriter xml( &buffer );
|
||||
xml.writeNamespace(davUri, "d");
|
||||
xml.writeNamespace(ocUri, "oc");
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement(davUri, QStringLiteral("multistatus"));
|
||||
auto writeFileResponse = [&](const FileInfo &fileInfo) {
|
||||
xml.writeStartElement(davUri, QStringLiteral("response"));
|
||||
|
||||
xml.writeTextElement(davUri, QStringLiteral("href"), "/owncloud/remote.php/webdav/" + fileInfo.path());
|
||||
xml.writeStartElement(davUri, QStringLiteral("propstat"));
|
||||
xml.writeStartElement(davUri, QStringLiteral("prop"));
|
||||
|
||||
if (fileInfo.isDir) {
|
||||
xml.writeStartElement(davUri, QStringLiteral("resourcetype"));
|
||||
xml.writeEmptyElement(davUri, QStringLiteral("collection"));
|
||||
xml.writeEndElement(); // resourcetype
|
||||
} else
|
||||
xml.writeEmptyElement(davUri, QStringLiteral("resourcetype"));
|
||||
|
||||
auto gmtDate = fileInfo.lastModified.toTimeZone(QTimeZone("GMT"));
|
||||
auto stringDate = gmtDate.toString("ddd, dd MMM yyyy HH:mm:ss 'GMT'");
|
||||
xml.writeTextElement(davUri, QStringLiteral("getlastmodified"), stringDate);
|
||||
xml.writeTextElement(davUri, QStringLiteral("getcontentlength"), QString::number(fileInfo.size));
|
||||
xml.writeTextElement(davUri, QStringLiteral("getetag"), fileInfo.etag);
|
||||
xml.writeTextElement(ocUri, QStringLiteral("permissions"), fileInfo.isShared ? QStringLiteral("SRDNVCKW") : QStringLiteral("RDNVCKW"));
|
||||
xml.writeEndElement(); // prop
|
||||
xml.writeTextElement(davUri, QStringLiteral("status"), "HTTP/1.1 200 OK");
|
||||
xml.writeEndElement(); // propstat
|
||||
xml.writeEndElement(); // response
|
||||
};
|
||||
|
||||
Q_ASSERT(request.url().path().startsWith(sRootUrl.path()));
|
||||
QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
const FileInfo *fileInfo = remoteRootFileInfo.find(fileName);
|
||||
|
||||
writeFileResponse(*fileInfo);
|
||||
foreach(const FileInfo &childFileInfo, fileInfo->children)
|
||||
writeFileResponse(childFileInfo);
|
||||
xml.writeEndElement(); // multistatus
|
||||
xml.writeEndDocument();
|
||||
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
setHeader(QNetworkRequest::ContentLengthHeader, payload.size());
|
||||
setHeader(QNetworkRequest::ContentTypeHeader, "application/xml; charset=utf-8");
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 207);
|
||||
setFinished(true);
|
||||
emit metaDataChanged();
|
||||
if (bytesAvailable())
|
||||
emit readyRead();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
|
||||
qint64 bytesAvailable() const override { return payload.size() + QIODevice::bytesAvailable(); }
|
||||
qint64 readData(char *data, qint64 maxlen) override {
|
||||
qint64 len = std::min(qint64{payload.size()}, maxlen);
|
||||
strncpy(data, payload.constData(), len);
|
||||
payload.remove(0, len);
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
class FakePutReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
FileInfo *fileInfo;
|
||||
public:
|
||||
FakePutReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, const QByteArray &putPayload, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
Q_ASSERT(request.url().path().startsWith(sRootUrl.path()));
|
||||
QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
if ((fileInfo = remoteRootFileInfo.find(fileName))) {
|
||||
fileInfo->size = putPayload.size();
|
||||
fileInfo->contentChar = putPayload.at(0);
|
||||
} else {
|
||||
// Assume that the file is filled with the same character
|
||||
fileInfo = remoteRootFileInfo.create(fileName, putPayload.size(), putPayload.at(0));
|
||||
}
|
||||
|
||||
if (!fileInfo) {
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
setRawHeader("OC-ETag", fileInfo->etag.toLatin1());
|
||||
setRawHeader("ETag", fileInfo->etag.toLatin1());
|
||||
setRawHeader("X-OC-MTime", "accepted"); // Prevents Q_ASSERT(!_runningNow) since we'll call PropagateItemJob::done twice in that case.
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
|
||||
class FakeMkcolReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
FileInfo *fileInfo;
|
||||
public:
|
||||
FakeMkcolReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
Q_ASSERT(request.url().path().startsWith(sRootUrl.path()));
|
||||
QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
fileInfo = remoteRootFileInfo.createDir(fileName);
|
||||
|
||||
if (!fileInfo) {
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
// FIXME: setRawHeader("OC-FileId", fileInfo->???);
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 201);
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
|
||||
class FakeDeleteReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FakeDeleteReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
Q_ASSERT(request.url().path().startsWith(sRootUrl.path()));
|
||||
QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
remoteRootFileInfo.remove(fileName);
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 204);
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
|
||||
class FakeGetReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
const FileInfo *fileInfo;
|
||||
QByteArray payload;
|
||||
|
||||
FakeGetReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
Q_ASSERT(request.url().path().startsWith(sRootUrl.path()));
|
||||
QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
fileInfo = remoteRootFileInfo.find(fileName);
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
payload.fill(fileInfo->contentChar, fileInfo->size);
|
||||
setHeader(QNetworkRequest::ContentLengthHeader, payload.size());
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
|
||||
setRawHeader("OC-ETag", fileInfo->etag.toLatin1());
|
||||
setRawHeader("ETag", fileInfo->etag.toLatin1());
|
||||
emit metaDataChanged();
|
||||
if (bytesAvailable())
|
||||
emit readyRead();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 bytesAvailable() const override { return payload.size() + QIODevice::bytesAvailable(); }
|
||||
|
||||
qint64 readData(char *data, qint64 maxlen) override {
|
||||
qint64 len = std::min(qint64{payload.size()}, maxlen);
|
||||
strncpy(data, payload.constData(), len);
|
||||
payload.remove(0, len);
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
class FakeErrorReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FakeErrorReply(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 500);
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
|
||||
class FakeQNAM : public QNetworkAccessManager
|
||||
{
|
||||
FileInfo _remoteRootFileInfo;
|
||||
QStringList _errorPaths;
|
||||
public:
|
||||
FakeQNAM(FileInfo initialRoot) : _remoteRootFileInfo{std::move(initialRoot)} { }
|
||||
FileInfo ¤tRemoteState() { return _remoteRootFileInfo; }
|
||||
QStringList &errorPaths() { return _errorPaths; }
|
||||
|
||||
protected:
|
||||
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
|
||||
QIODevice *outgoingData = 0) {
|
||||
const QString fileName = request.url().path().mid(sRootUrl.path().length());
|
||||
if (_errorPaths.contains(fileName))
|
||||
return new FakeErrorReply{op, request, this};
|
||||
|
||||
auto verb = request.attribute(QNetworkRequest::CustomVerbAttribute);
|
||||
if (verb == QLatin1String("PROPFIND"))
|
||||
// Ignore outgoingData always returning somethign good enough, works for now.
|
||||
return new FakePropfindReply{_remoteRootFileInfo, op, request, this};
|
||||
else if (verb == QLatin1String("GET"))
|
||||
return new FakeGetReply{_remoteRootFileInfo, op, request, this};
|
||||
else if (verb == QLatin1String("PUT"))
|
||||
return new FakePutReply{_remoteRootFileInfo, op, request, outgoingData->readAll(), this};
|
||||
else if (verb == QLatin1String("MKCOL"))
|
||||
return new FakeMkcolReply{_remoteRootFileInfo, op, request, this};
|
||||
else if (verb == QLatin1String("DELETE"))
|
||||
return new FakeDeleteReply{_remoteRootFileInfo, op, request, this};
|
||||
else {
|
||||
qDebug() << verb << outgoingData;
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FakeCredentials : public OCC::AbstractCredentials
|
||||
{
|
||||
QNetworkAccessManager *_qnam;
|
||||
public:
|
||||
FakeCredentials(QNetworkAccessManager *qnam) : _qnam{qnam} { }
|
||||
virtual bool changed(AbstractCredentials *) const { return false; }
|
||||
virtual QString authType() const { return "test"; }
|
||||
virtual QString user() const { return "admin"; }
|
||||
virtual QNetworkAccessManager* getQNAM() const { return _qnam; }
|
||||
virtual bool ready() const { return true; }
|
||||
virtual void fetchFromKeychain() { }
|
||||
virtual void askFromUser() { }
|
||||
virtual bool stillValid(QNetworkReply *) { return true; }
|
||||
virtual void persist() { }
|
||||
virtual void invalidateToken() { }
|
||||
virtual void forgetSensitiveData() { }
|
||||
};
|
||||
|
||||
class FakeFolder
|
||||
{
|
||||
QTemporaryDir _tempDir;
|
||||
DiskFileModifier _localModifier;
|
||||
// FIXME: Clarify ownership, double delete
|
||||
FakeQNAM *_fakeQnam;
|
||||
OCC::AccountPtr _account;
|
||||
std::unique_ptr<OCC::SyncJournalDb> _journalDb;
|
||||
std::unique_ptr<OCC::SyncEngine> _syncEngine;
|
||||
|
||||
public:
|
||||
FakeFolder(const FileInfo &fileTemplate)
|
||||
: _localModifier(_tempDir.path())
|
||||
{
|
||||
// Needs to be done once
|
||||
OCC::SyncEngine::minimumFileAgeForUpload = 0;
|
||||
csync_set_log_level(11);
|
||||
|
||||
QDir rootDir{_tempDir.path()};
|
||||
toDisk(rootDir, fileTemplate);
|
||||
|
||||
_fakeQnam = new FakeQNAM(fileTemplate);
|
||||
_account = OCC::Account::create();
|
||||
_account->setUrl(QUrl(QStringLiteral("http://admin:admin@localhost/owncloud")));
|
||||
_account->setCredentials(new FakeCredentials{_fakeQnam});
|
||||
|
||||
_journalDb.reset(new OCC::SyncJournalDb(localPath()));
|
||||
_syncEngine.reset(new OCC::SyncEngine(_account, localPath(), sRootUrl, "", _journalDb.get()));
|
||||
|
||||
// A new folder will update the local file state database on first sync.
|
||||
// To have a state matching what users will encounter, we have to a sync
|
||||
// using an identical local/remote file tree first.
|
||||
syncOnce();
|
||||
}
|
||||
|
||||
OCC::SyncEngine &syncEngine() const { return *_syncEngine; }
|
||||
|
||||
FileModifier &localModifier() { return _localModifier; }
|
||||
FileModifier &remoteModifier() { return _fakeQnam->currentRemoteState(); }
|
||||
FileInfo currentLocalState() {
|
||||
QDir rootDir{_tempDir.path()};
|
||||
FileInfo rootTemplate;
|
||||
fromDisk(rootDir, rootTemplate);
|
||||
return rootTemplate;
|
||||
}
|
||||
|
||||
FileInfo currentRemoteState() { return _fakeQnam->currentRemoteState(); }
|
||||
|
||||
QStringList &serverErrorPaths() { return _fakeQnam->errorPaths(); }
|
||||
|
||||
QString localPath() const {
|
||||
// SyncEngine wants a trailing slash
|
||||
if (_tempDir.path().endsWith('/'))
|
||||
return _tempDir.path();
|
||||
return _tempDir.path() + '/';
|
||||
}
|
||||
|
||||
void scheduleSync() {
|
||||
// Have to be done async, else, an error before exec() does not terminate the event loop.
|
||||
QMetaObject::invokeMethod(_syncEngine.get(), "startSync", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void execUntilBeforePropagation() {
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(aboutToPropagate(SyncFileItemVector&)));
|
||||
QVERIFY(spy.wait());
|
||||
}
|
||||
|
||||
void execUntilItemCompleted(const QString &relativePath) {
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QElapsedTimer t;
|
||||
t.start();
|
||||
while (t.elapsed() < 5000) {
|
||||
spy.clear();
|
||||
QVERIFY(spy.wait());
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
auto item = args[0].value<OCC::SyncFileItem>();
|
||||
if (item.destination() == relativePath)
|
||||
return;
|
||||
}
|
||||
}
|
||||
QVERIFY(false);
|
||||
}
|
||||
|
||||
void execUntilFinished() {
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(finished(bool)));
|
||||
QVERIFY(spy.wait());
|
||||
}
|
||||
|
||||
void syncOnce() {
|
||||
scheduleSync();
|
||||
execUntilFinished();
|
||||
}
|
||||
|
||||
private:
|
||||
static void toDisk(QDir &dir, const FileInfo &templateFi) {
|
||||
foreach (const FileInfo &child, templateFi.children) {
|
||||
if (child.isDir) {
|
||||
QDir subDir(dir);
|
||||
dir.mkdir(child.name);
|
||||
subDir.cd(child.name);
|
||||
toDisk(subDir, child);
|
||||
} else {
|
||||
QFile file{dir.filePath(child.name)};
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(QByteArray{}.fill(child.contentChar, child.size));
|
||||
file.close();
|
||||
OCC::FileSystem::setModTime(file.fileName(), OCC::Utility::qDateTimeToTime_t(child.lastModified));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fromDisk(QDir &dir, FileInfo &templateFi) {
|
||||
foreach (const QFileInfo &diskChild, dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)) {
|
||||
if (diskChild.isDir()) {
|
||||
QDir subDir = dir;
|
||||
subDir.cd(diskChild.fileName());
|
||||
templateFi.children.insert(diskChild.fileName(), FileInfo{diskChild.fileName()});
|
||||
fromDisk(subDir, templateFi.children.last());
|
||||
} else {
|
||||
QFile f{diskChild.filePath()};
|
||||
f.open(QFile::ReadOnly);
|
||||
char contentChar = f.read(1).at(0);
|
||||
templateFi.children.insert(diskChild.fileName(), FileInfo{diskChild.fileName(), diskChild.size(), contentChar});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// QTest::toString overloads
|
||||
namespace OCC {
|
||||
inline char *toString(const SyncFileStatus &s) {
|
||||
return QTest::toString(QString("SyncFileStatus(" + s.toSocketAPIString() + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
inline void addFiles(QStringList &dest, const FileInfo &fi)
|
||||
{
|
||||
if (fi.isDir) {
|
||||
dest += QString("%1 - dir").arg(fi.name);
|
||||
foreach (const FileInfo &fi, fi.children)
|
||||
addFiles(dest, fi);
|
||||
} else {
|
||||
dest += QString("%1 - %2 %3-bytes").arg(fi.name).arg(fi.size).arg(fi.contentChar);
|
||||
}
|
||||
}
|
||||
|
||||
inline char *toString(const FileInfo &fi)
|
||||
{
|
||||
QStringList files;
|
||||
foreach (const FileInfo &fi, fi.children)
|
||||
addFiles(files, fi);
|
||||
return QTest::toString(QString("FileInfo with %1 files(%2)").arg(files.size()).arg(files.join(", ")));
|
||||
}
|
||||
@@ -26,6 +26,7 @@ private slots:
|
||||
bool excludeHidden = true;
|
||||
bool keepHidden = false;
|
||||
|
||||
bool x = excluded.isExcluded("/a/b", "/a", keepHidden);
|
||||
QVERIFY(!excluded.isExcluded("/a/b", "/a", keepHidden));
|
||||
QVERIFY(!excluded.isExcluded("/a/b~", "/a", keepHidden));
|
||||
QVERIFY(!excluded.isExcluded("/a/.b", "/a", keepHidden));
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QtTest>
|
||||
#include "syncenginetestutils.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
bool itemDidComplete(const QSignalSpy &spy, const QString &path)
|
||||
{
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
SyncFileItem item = args[0].value<SyncFileItem>();
|
||||
if (item.destination() == path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool itemDidCompleteSuccessfully(const QSignalSpy &spy, const QString &path)
|
||||
{
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
SyncFileItem item = args[0].value<SyncFileItem>();
|
||||
if (item.destination() == path)
|
||||
return item._status == SyncFileItem::Success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class TestSyncEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testFileDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.remoteModifier().insert("A/a0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testFileUpload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.localModifier().insert("A/a0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testDirDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.remoteModifier().mkdir("Y");
|
||||
fakeFolder.remoteModifier().mkdir("Z");
|
||||
fakeFolder.remoteModifier().insert("Z/d0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Y"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z/d0"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testDirUpload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.localModifier().mkdir("Y");
|
||||
fakeFolder.localModifier().mkdir("Z");
|
||||
fakeFolder.localModifier().insert("Z/d0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Y"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z/d0"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testLocalDelete() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.remoteModifier().remove("A/a1");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testRemoteDelete() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
fakeFolder.localModifier().remove("A/a1");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void testEmlLocalChecksum() {
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
fakeFolder.localModifier().insert("a1.eml", 64, 'A');
|
||||
fakeFolder.localModifier().insert("a2.eml", 64, 'A');
|
||||
fakeFolder.localModifier().insert("a3.eml", 64, 'A');
|
||||
// Upload and calculate the checksums
|
||||
// fakeFolder.syncOnce();
|
||||
fakeFolder.syncOnce();
|
||||
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
// Touch the file without changing the content, shouldn't upload
|
||||
fakeFolder.localModifier().setContents("a1.eml", 'A');
|
||||
// Change the content/size
|
||||
fakeFolder.localModifier().setContents("a2.eml", 'B');
|
||||
fakeFolder.localModifier().appendByte("a3.eml");
|
||||
fakeFolder.syncOnce();
|
||||
|
||||
QVERIFY(!itemDidComplete(completeSpy, "a1.eml"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "a2.eml"));
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "a3.eml"));
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(TestSyncEngine)
|
||||
#include "testsyncengine.moc"
|
||||
@@ -1,404 +0,0 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QtTest>
|
||||
#include "syncenginetestutils.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
class StatusPushSpy : public QSignalSpy
|
||||
{
|
||||
SyncEngine &_syncEngine;
|
||||
public:
|
||||
StatusPushSpy(SyncEngine &syncEngine)
|
||||
: QSignalSpy(&syncEngine.syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString&, SyncFileStatus)))
|
||||
, _syncEngine(syncEngine)
|
||||
{ }
|
||||
|
||||
SyncFileStatus statusOf(const QString &relativePath) const {
|
||||
QFileInfo file(_syncEngine.localPath(), relativePath);
|
||||
// Start from the end to get the latest status
|
||||
for (int i = size() - 1; i >= 0; --i) {
|
||||
if (QFileInfo(at(i)[0].toString()) == file)
|
||||
return at(i)[1].value<SyncFileStatus>();
|
||||
}
|
||||
return SyncFileStatus();
|
||||
}
|
||||
};
|
||||
|
||||
class TestSyncFileStatusTracker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void verifyThatPushMatchesPull(const FakeFolder &fakeFolder, const StatusPushSpy &statusSpy) {
|
||||
QString root = fakeFolder.localPath();
|
||||
QDirIterator it(root, QDir::AllEntries | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString filePath = it.next().mid(root.size());
|
||||
SyncFileStatus pushedStatus = statusSpy.statusOf(filePath);
|
||||
if (pushedStatus != SyncFileStatus())
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus(filePath), pushedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
void parentsGetSyncStatusUploadDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.localModifier().appendByte("B/b1");
|
||||
fakeFolder.remoteModifier().appendByte("C/c1");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C/c1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("B/b2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("C/c2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
statusSpy.clear();
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C/c1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetSyncStatusNewFileUploadDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.localModifier().insert("B/b0");
|
||||
fakeFolder.remoteModifier().insert("C/c0");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C/c0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("B/b1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("C/c1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
statusSpy.clear();
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C/c0"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetSyncStatusNewDirDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.remoteModifier().mkdir("D");
|
||||
fakeFolder.remoteModifier().insert("D/d0");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
|
||||
fakeFolder.execUntilItemCompleted("D");
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetSyncStatusNewDirUpload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.localModifier().mkdir("D");
|
||||
fakeFolder.localModifier().insert("D/d0");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
|
||||
fakeFolder.execUntilItemCompleted("D");
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("D"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("D/d0"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetSyncStatusDeleteUpDown() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.remoteModifier().remove("B/b1");
|
||||
fakeFolder.localModifier().remove("C/c1");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
// Discovered as remotely removed, pending for local removal.
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("B/b2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("C/c2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
statusSpy.clear();
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void warningStatusForExcludedFile() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().excludedFiles().addExcludeExpr("A/a1");
|
||||
fakeFolder.syncEngine().excludedFiles().addExcludeExpr("B");
|
||||
fakeFolder.localModifier().appendByte("A/a1");
|
||||
fakeFolder.localModifier().appendByte("B/b1");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QEXPECT_FAIL("", "csync will stop at ignored directories without traversing children, so we don't currently push the status for newly ignored children of an ignored directory.", Continue);
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QEXPECT_FAIL("", "csync will stop at ignored directories without traversing children, so we don't currently push the status for newly ignored children of an ignored directory.", Continue);
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QEXPECT_FAIL("", "csync will stop at ignored directories without traversing children, so we don't currently push the status for newly ignored children of an ignored directory.", Continue);
|
||||
QCOMPARE(statusSpy.statusOf("B/b2"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
statusSpy.clear();
|
||||
|
||||
// Clears the exclude expr above
|
||||
fakeFolder.syncEngine().excludedFiles().reloadExcludes();
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
statusSpy.clear();
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B/b1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetWarningStatusForError() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.serverErrorPaths().append("A/a1");
|
||||
fakeFolder.serverErrorPaths().append("B/b0");
|
||||
fakeFolder.localModifier().appendByte("A/a1");
|
||||
fakeFolder.localModifier().insert("B/b0");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
statusSpy.clear();
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
statusSpy.clear();
|
||||
|
||||
// Remove the error and start a second sync, the blacklist should kick in
|
||||
fakeFolder.serverErrorPaths().clear();
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
// A/a1 and B/b0 should be on the black list for the next few seconds
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
statusSpy.clear();
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
statusSpy.clear();
|
||||
|
||||
// Start a third sync, this time together with a real file to sync
|
||||
fakeFolder.localModifier().appendByte("C/c1");
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
// The root should show SYNC even though there is an error underneath,
|
||||
// since C/c1 is syncing and the SYNC status has priority.
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("C/c1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
statusSpy.clear();
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a2"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(statusSpy.statusOf("C"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("C/c1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
statusSpy.clear();
|
||||
|
||||
// Another sync after clearing the blacklist entry, everything should return to order.
|
||||
fakeFolder.syncEngine().journal()->wipeErrorBlacklistEntry("A/a1");
|
||||
fakeFolder.syncEngine().journal()->wipeErrorBlacklistEntry("B/b0");
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
statusSpy.clear();
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("B/b0"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
|
||||
void parentsGetWarningStatusForError_SibblingStartsWithPath() {
|
||||
// A is a parent of A/a1, but A/a is not even if it's a substring of A/a1
|
||||
FakeFolder fakeFolder{{QString{},{
|
||||
{QStringLiteral("A"), {
|
||||
{QStringLiteral("a"), 4},
|
||||
{QStringLiteral("a1"), 4}
|
||||
}}}}};
|
||||
fakeFolder.serverErrorPaths().append("A/a1");
|
||||
fakeFolder.localModifier().appendByte("A/a1");
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
// The SyncFileStatusTraker won't push any status for all of them, test with a pull.
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a1"), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
// We use string matching for paths in the implementation,
|
||||
// an error should affect only parents and not every path that starts with the problem path.
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a1"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||
QCOMPARE(fakeFolder.syncEngine().syncFileStatusTracker().fileStatus("A/a"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
}
|
||||
|
||||
void sharedStatus() {
|
||||
SyncFileStatus sharedUpToDateStatus(SyncFileStatus::StatusUpToDate);
|
||||
sharedUpToDateStatus.setSharedWithMe(true);
|
||||
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.remoteModifier().insert("S/s0");
|
||||
fakeFolder.remoteModifier().appendByte("S/s1");
|
||||
StatusPushSpy statusSpy(fakeFolder.syncEngine());
|
||||
|
||||
fakeFolder.scheduleSync();
|
||||
fakeFolder.execUntilBeforePropagation();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusSync));
|
||||
// We don't care about the shared flag for the sync status,
|
||||
// Mac and Windows won't show it and we can't know it for new files.
|
||||
QCOMPARE(statusSpy.statusOf("S").tag(), SyncFileStatus::StatusSync);
|
||||
QCOMPARE(statusSpy.statusOf("S/s0").tag(), SyncFileStatus::StatusSync);
|
||||
QCOMPARE(statusSpy.statusOf("S/s1").tag(), SyncFileStatus::StatusSync);
|
||||
|
||||
fakeFolder.execUntilFinished();
|
||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||
QCOMPARE(statusSpy.statusOf("S"), sharedUpToDateStatus);
|
||||
QEXPECT_FAIL("", "We currently only know if a new file is shared on the second sync, after a PROPFIND.", Continue);
|
||||
QCOMPARE(statusSpy.statusOf("S/s0"), sharedUpToDateStatus);
|
||||
QCOMPARE(statusSpy.statusOf("S/s1"), sharedUpToDateStatus);
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(TestSyncFileStatusTracker)
|
||||
#include "testsyncfilestatustracker.moc"
|
||||
+47
-47
@@ -522,7 +522,7 @@
|
||||
<context>
|
||||
<name>OCC::CleanupPollsJob</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="772"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="779"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Error en escriure les metadades a la base de dades</translation>
|
||||
</message>
|
||||
@@ -892,7 +892,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation>Error en carregar la llista de carpetes del servidor.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="204"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="205"/>
|
||||
<source>Signed out</source>
|
||||
<translation>S'ha desconnectat</translation>
|
||||
</message>
|
||||
@@ -902,96 +902,96 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="169"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="170"/>
|
||||
<source>Fetching folder list from server...</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="832"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="841"/>
|
||||
<source>Checking for changes in '%1'</source>
|
||||
<translation>S'està comprovant els canvis a '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="867"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="876"/>
|
||||
<source>, '%1'</source>
|
||||
<extracomment>Build a list of file names</extracomment>
|
||||
<translation>, '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="870"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="879"/>
|
||||
<source>'%1'</source>
|
||||
<extracomment>Argument is a file name</extracomment>
|
||||
<translation>'%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="895"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="904"/>
|
||||
<source>Syncing %1</source>
|
||||
<extracomment>Example text: "Syncing 'foo.txt', 'bar.txt'"</extracomment>
|
||||
<translation>S'està sincronitzant %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="897"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="907"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="906"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="916"/>
|
||||
<source>, </source>
|
||||
<translation>, </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="901"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<source>download %1/s</source>
|
||||
<extracomment>Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>descarrega %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="903"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<source>u2193 %1/s</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
|
||||
<source>upload %1/s</source>
|
||||
<extracomment>Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>pujada %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<source>u2191 %1/s</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="917"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="926"/>
|
||||
<source>%1 %2 (%3 of %4)</source>
|
||||
<extracomment>Example text: "uploading foobar.png (2MB of 2MB)"</extracomment>
|
||||
<translation>%1 %2 (%3 de %4)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="930"/>
|
||||
<source>%1 %2</source>
|
||||
<extracomment>Example text: "uploading foobar.png"</extracomment>
|
||||
<translation>%1 %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="938"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="947"/>
|
||||
<source>%5 left, %1 of %2, file %3 of %4</source>
|
||||
<extracomment>Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"</extracomment>
|
||||
<translation>%5 pendent, %1 de %2, fitxer %3 de %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="944"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="953"/>
|
||||
<source>file %1 of %2</source>
|
||||
<translation>fitxer %1 de %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="984"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="993"/>
|
||||
<source>Waiting...</source>
|
||||
<translation>S'està esperant...</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="986"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="995"/>
|
||||
<source>Waiting for %n other folder(s)...</source>
|
||||
<translation><numerusform>S'està esperant %n altra carpeta...</numerusform><numerusform>S'està esperant %n altres carpetes</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="992"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="1001"/>
|
||||
<source>Preparing to sync...</source>
|
||||
<translation>S'està preparant per sincronitzar...</translation>
|
||||
</message>
|
||||
@@ -1916,7 +1916,7 @@ No és aconsellada usar-la.</translation>
|
||||
<context>
|
||||
<name>OCC::PropagateDirectory</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="712"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="718"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Error en escriure les metadades a la base de dades</translation>
|
||||
</message>
|
||||
@@ -1954,17 +1954,17 @@ No és aconsellada usar-la.</translation>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="693"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="694"/>
|
||||
<source>File %1 cannot be saved because of a local file name clash!</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="741"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="742"/>
|
||||
<source>File has changed since discovery</source>
|
||||
<translation>El fitxer ha canviat des de que es va descobrir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="791"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="792"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Error en escriure les metadades a la base de dades</translation>
|
||||
</message>
|
||||
@@ -2450,18 +2450,18 @@ No és aconsellada usar-la.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="366"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="412"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="413"/>
|
||||
<source>Public sh&aring requires a password</source>
|
||||
<translation>La comp&artició pública requereix una contrasenya</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="434"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="435"/>
|
||||
<source>Please Set Password</source>
|
||||
<translation>Establiu la contrasenya</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="498"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="499"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="500"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="501"/>
|
||||
<source>&Share link</source>
|
||||
<translation>Com&parteix l'enllaç</translation>
|
||||
</message>
|
||||
@@ -2871,12 +2871,12 @@ No és aconsellada usar-la.</translation>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1134"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1139"/>
|
||||
<source>Not allowed because you don't have permission to add parent folder</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1141"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1146"/>
|
||||
<source>Not allowed because you don't have permission to add files in that folder</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
@@ -2981,64 +2981,64 @@ No és aconsellada usar-la.</translation>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="787"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="791"/>
|
||||
<source>Unable to read from the sync journal.</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="833"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="837"/>
|
||||
<source>Cannot open the sync journal</source>
|
||||
<translation>No es pot obrir el diari de sincronització</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="889"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="894"/>
|
||||
<source>File name contains at least one invalid character</source>
|
||||
<translation>El nom del fitxer conté al menys un caràcter invàlid</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1093"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1100"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1098"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1105"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation>S'ignora degut al filtre a «Trieu què sincronitzar»</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1119"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1124"/>
|
||||
<source>Not allowed because you don't have permission to add subfolders to that folder</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1161"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1166"/>
|
||||
<source>Not allowed to upload this file because it is read-only on the server, restoring</source>
|
||||
<translation>No es permet pujar aquest fitxer perquè només és de lectura en el servidor, es restaura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1178"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1198"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1183"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1203"/>
|
||||
<source>Not allowed to remove, restoring</source>
|
||||
<translation>No es permet l'eliminació, es restaura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1211"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1216"/>
|
||||
<source>Local files and share folder removed.</source>
|
||||
<translation>Fitxers locals i carpeta compartida esborrats.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1267"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1272"/>
|
||||
<source>Move not allowed, item restored</source>
|
||||
<translation>No es permet moure'l, l'element es restaura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1278"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1283"/>
|
||||
<source>Move not allowed because %1 is read-only</source>
|
||||
<translation>No es permet moure perquè %1 només és de lectura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the destination</source>
|
||||
<translation>el destí</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the source</source>
|
||||
<translation>l'origen</translation>
|
||||
</message>
|
||||
@@ -3068,7 +3068,7 @@ No és aconsellada usar-la.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="289"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<source><p>Copyright ownCloud GmbH</p></source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
@@ -3293,8 +3293,8 @@ No és aconsellada usar-la.</translation>
|
||||
<name>OCC::ownCloudTheme</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="47"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Versió %2. Per més informació visiteu <a href="%3">%4</a></p><p><small>Per Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz i altres.</small></p><p>Copyright ownCloud, Inc.</p><p>amb llicència GNU General Public License (GPL) versió 2.0<br/>ownCloud i el logo d'ownCloud són marques registrades d'ownCloud, Inc. als Estats Units, altres països, o ambdós.</p></translation>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud GmbH</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
+48
-48
@@ -522,7 +522,7 @@
|
||||
<context>
|
||||
<name>OCC::CleanupPollsJob</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="772"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="779"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Chyba zápisu metadat do databáze</translation>
|
||||
</message>
|
||||
@@ -894,7 +894,7 @@ Pokračováním v synchronizaci způsobí přepsání všech vašich souborů st
|
||||
<translation>Chyba při načítání seznamu adresářů ze serveru.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="204"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="205"/>
|
||||
<source>Signed out</source>
|
||||
<translation>Odhlášeno</translation>
|
||||
</message>
|
||||
@@ -904,96 +904,96 @@ Pokračováním v synchronizaci způsobí přepsání všech vašich souborů st
|
||||
<translation>Přidání adresáře je vypnuto, protože již synchronizujete všechny své soubory. Pokud chcete synchronizovat pouze některé adresáře, odstraňte aktuálně nastavený kořenový adresář.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="169"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="170"/>
|
||||
<source>Fetching folder list from server...</source>
|
||||
<translation>Načítání seznamu adresářů ze serveru...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="832"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="841"/>
|
||||
<source>Checking for changes in '%1'</source>
|
||||
<translation>Kontrola změn v '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="867"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="876"/>
|
||||
<source>, '%1'</source>
|
||||
<extracomment>Build a list of file names</extracomment>
|
||||
<translation>, '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="870"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="879"/>
|
||||
<source>'%1'</source>
|
||||
<extracomment>Argument is a file name</extracomment>
|
||||
<translation>'%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="895"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="904"/>
|
||||
<source>Syncing %1</source>
|
||||
<extracomment>Example text: "Syncing 'foo.txt', 'bar.txt'"</extracomment>
|
||||
<translation>Synchronizuji %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="897"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="907"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="906"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="916"/>
|
||||
<source>, </source>
|
||||
<translation>, </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="901"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<source>download %1/s</source>
|
||||
<extracomment>Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>stahování %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="903"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<source>u2193 %1/s</source>
|
||||
<translation>u2193 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
|
||||
<source>upload %1/s</source>
|
||||
<extracomment>Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>nahrávání %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<source>u2191 %1/s</source>
|
||||
<translation>u2191 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="917"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="926"/>
|
||||
<source>%1 %2 (%3 of %4)</source>
|
||||
<extracomment>Example text: "uploading foobar.png (2MB of 2MB)"</extracomment>
|
||||
<translation>%1 %2 (%3 ze %4)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="930"/>
|
||||
<source>%1 %2</source>
|
||||
<extracomment>Example text: "uploading foobar.png"</extracomment>
|
||||
<translation>%1 %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="938"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="947"/>
|
||||
<source>%5 left, %1 of %2, file %3 of %4</source>
|
||||
<extracomment>Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"</extracomment>
|
||||
<translation>%5 zbývá, %1 ze %2, soubor %3 z %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="944"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="953"/>
|
||||
<source>file %1 of %2</source>
|
||||
<translation>soubor %1 z %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="984"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="993"/>
|
||||
<source>Waiting...</source>
|
||||
<translation>Chvíli strpení...</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="986"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="995"/>
|
||||
<source>Waiting for %n other folder(s)...</source>
|
||||
<translation><numerusform>Čeká se na %n další adresář...</numerusform><numerusform>Čeká se na %n další adresáře...</numerusform><numerusform>Čeká se na %n dalších adresářů...</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="992"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="1001"/>
|
||||
<source>Preparing to sync...</source>
|
||||
<translation>Synchronizace se připravuje...</translation>
|
||||
</message>
|
||||
@@ -1918,7 +1918,7 @@ Nedoporučuje se jí používat.</translation>
|
||||
<context>
|
||||
<name>OCC::PropagateDirectory</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="712"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="718"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Chyba zápisu metadat do databáze</translation>
|
||||
</message>
|
||||
@@ -1956,17 +1956,17 @@ Nedoporučuje se jí používat.</translation>
|
||||
<translation>Stažený soubor je prázdný, přestože server oznámil, že měl být %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="693"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="694"/>
|
||||
<source>File %1 cannot be saved because of a local file name clash!</source>
|
||||
<translation>Soubor %1 nemohl být uložen z důvodu kolize názvu se souborem v místním systému!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="741"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="742"/>
|
||||
<source>File has changed since discovery</source>
|
||||
<translation>Soubor se mezitím změnil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="791"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="792"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Chyba zápisu metadat do databáze</translation>
|
||||
</message>
|
||||
@@ -2452,18 +2452,18 @@ Nedoporučuje se jí používat.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="366"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="412"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="413"/>
|
||||
<source>Public sh&aring requires a password</source>
|
||||
<translation>Veřejné s&dílení vyžaduje heslo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="434"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="435"/>
|
||||
<source>Please Set Password</source>
|
||||
<translation>Nastavte prosím heslo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="498"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="499"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="500"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="501"/>
|
||||
<source>&Share link</source>
|
||||
<translation>&Sdílet odkaz</translation>
|
||||
</message>
|
||||
@@ -2873,12 +2873,12 @@ Nedoporučuje se jí používat.</translation>
|
||||
<translation>Je dostupných pouze %1, pro spuštění je potřeba alespoň %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1134"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1139"/>
|
||||
<source>Not allowed because you don't have permission to add parent folder</source>
|
||||
<translation>Není povoleno, protože nemáte oprávnění vytvořit nadřazený adresář</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1141"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1146"/>
|
||||
<source>Not allowed because you don't have permission to add files in that folder</source>
|
||||
<translation>Není povoleno, protože nemáte oprávnění přidávat soubory do tohoto adresáře</translation>
|
||||
</message>
|
||||
@@ -2983,64 +2983,64 @@ Nedoporučuje se jí používat.</translation>
|
||||
<translation>Nelze načíst blacklist z místní databáze</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="787"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="791"/>
|
||||
<source>Unable to read from the sync journal.</source>
|
||||
<translation>Nelze číst ze žurnálu synchronizace.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="833"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="837"/>
|
||||
<source>Cannot open the sync journal</source>
|
||||
<translation>Nelze otevřít synchronizační žurnál</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="889"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="894"/>
|
||||
<source>File name contains at least one invalid character</source>
|
||||
<translation>Jméno souboru obsahuje aelspoň jeden neplatný znak</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1093"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1100"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1098"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1105"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation>Ignorováno podle nastavení "vybrat co synchronizovat"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1119"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1124"/>
|
||||
<source>Not allowed because you don't have permission to add subfolders to that folder</source>
|
||||
<translation>Není povoleno, protože nemáte oprávnění přidávat podadresáře do tohoto adresáře</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1161"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1166"/>
|
||||
<source>Not allowed to upload this file because it is read-only on the server, restoring</source>
|
||||
<translation>Není povoleno nahrát tento soubor, protože je na serveru uložen pouze pro čtení, obnovuji</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1178"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1198"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1183"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1203"/>
|
||||
<source>Not allowed to remove, restoring</source>
|
||||
<translation>Odstranění není povoleno, obnovuji</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1211"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1216"/>
|
||||
<source>Local files and share folder removed.</source>
|
||||
<translation>Místní soubory a sdílený adresář byly odstraněny.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1267"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1272"/>
|
||||
<source>Move not allowed, item restored</source>
|
||||
<translation>Přesun není povolen, položka obnovena</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1278"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1283"/>
|
||||
<source>Move not allowed because %1 is read-only</source>
|
||||
<translation>Přesun není povolen, protože %1 je pouze pro čtení</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the destination</source>
|
||||
<translation>cílové umístění</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the source</source>
|
||||
<translation>zdroj</translation>
|
||||
</message>
|
||||
@@ -3070,8 +3070,8 @@ Nedoporučuje se jí používat.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="289"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<translation><p>Copyright ownCloud, Incorporated</p></translation>
|
||||
<source><p>Copyright ownCloud GmbH</p></source>
|
||||
<translation><p>Copyright ownCloud GmbH</p></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="290"/>
|
||||
@@ -3295,8 +3295,8 @@ Nedoporučuje se jí používat.</translation>
|
||||
<name>OCC::ownCloudTheme</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="47"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Verze %2. Pro další informace navštivte <a href="%3">%4</a></p><p><small>Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz a další.</small></p><p>Copyright ownCloud, Inc.</p><p>Licencováno pod GNU General Public License (GPL) Version 2.0<br/>ownCloud a ownCloud logo jsou registrované obchodní známky ownCloud, Inc. ve Spojených státech, ostatních zemích nebo obojí</p></translation>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud GmbH</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Verze %2. Pro další informace navštivte <a href="%3">%4</a></p><p><small>Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz a další.</small></p><p>Copyright ownCloud GmbH</p><p>Licencováno pod GNU General Public License (GPL) Version 2.0<br/>ownCloud a ownCloud logo jsou registrované obchodní známky ownCloud, Inc. ve Spojených státech, ostatních zemích nebo obojí</p></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
+48
-48
@@ -522,7 +522,7 @@
|
||||
<context>
|
||||
<name>OCC::CleanupPollsJob</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="772"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="779"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Fehler beim Schreiben der Metadaten in die Datenbank</translation>
|
||||
</message>
|
||||
@@ -893,7 +893,7 @@ Wenn diese Synchronisation fortgesetzt wird, werden Dateien eventuell von älter
|
||||
<translation>Fehler beim Empfang der Ordnerliste vom Server.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="204"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="205"/>
|
||||
<source>Signed out</source>
|
||||
<translation>Abgemeldet</translation>
|
||||
</message>
|
||||
@@ -903,96 +903,96 @@ Wenn diese Synchronisation fortgesetzt wird, werden Dateien eventuell von älter
|
||||
<translation>Sie können keinen weiteren Ordner hinzufügen, da Sie bereits alle Dateien synchronisieren. Falls sie mehrere Ordner synchronisieren wollen, entferen Sie zunächst den konfigurierten Wurzel-Ordner.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="169"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="170"/>
|
||||
<source>Fetching folder list from server...</source>
|
||||
<translation>Empfange Orderliste vom Server...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="832"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="841"/>
|
||||
<source>Checking for changes in '%1'</source>
|
||||
<translation>Nach Änderungen suchen in '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="867"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="876"/>
|
||||
<source>, '%1'</source>
|
||||
<extracomment>Build a list of file names</extracomment>
|
||||
<translation>, '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="870"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="879"/>
|
||||
<source>'%1'</source>
|
||||
<extracomment>Argument is a file name</extracomment>
|
||||
<translation>'%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="895"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="904"/>
|
||||
<source>Syncing %1</source>
|
||||
<extracomment>Example text: "Syncing 'foo.txt', 'bar.txt'"</extracomment>
|
||||
<translation>Synchronisiere %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="897"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="907"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="906"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="916"/>
|
||||
<source>, </source>
|
||||
<translation>, </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="901"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<source>download %1/s</source>
|
||||
<extracomment>Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>Download %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="903"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<source>u2193 %1/s</source>
|
||||
<translation>u2193 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
|
||||
<source>upload %1/s</source>
|
||||
<extracomment>Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>Upload %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<source>u2191 %1/s</source>
|
||||
<translation>u2191 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="917"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="926"/>
|
||||
<source>%1 %2 (%3 of %4)</source>
|
||||
<extracomment>Example text: "uploading foobar.png (2MB of 2MB)"</extracomment>
|
||||
<translation>%1 %2 (%3 von %4)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="930"/>
|
||||
<source>%1 %2</source>
|
||||
<extracomment>Example text: "uploading foobar.png"</extracomment>
|
||||
<translation>%1 %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="938"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="947"/>
|
||||
<source>%5 left, %1 of %2, file %3 of %4</source>
|
||||
<extracomment>Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"</extracomment>
|
||||
<translation>%5 übrig, %1 von %2, Datei %3 von %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="944"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="953"/>
|
||||
<source>file %1 of %2</source>
|
||||
<translation>Datei %1 von %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="984"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="993"/>
|
||||
<source>Waiting...</source>
|
||||
<translation>Warte...</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="986"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="995"/>
|
||||
<source>Waiting for %n other folder(s)...</source>
|
||||
<translation><numerusform>Warte auf einen anderen Ordner</numerusform><numerusform>Warte auf %n andere Ordner</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="992"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="1001"/>
|
||||
<source>Preparing to sync...</source>
|
||||
<translation>Bereite Synchronisation vor...</translation>
|
||||
</message>
|
||||
@@ -1916,7 +1916,7 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
<context>
|
||||
<name>OCC::PropagateDirectory</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="712"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="718"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Fehler beim Schreiben der Metadaten in die Datenbank</translation>
|
||||
</message>
|
||||
@@ -1954,17 +1954,17 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
<translation>Die heruntergeladene Datei ist leer, obwohl der Server %1 als Größe übermittelt hat.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="693"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="694"/>
|
||||
<source>File %1 cannot be saved because of a local file name clash!</source>
|
||||
<translation>Die Datei %1 kann aufgrund eines Konfliktes mit dem lokalen Dateinamen nicht gespeichert geladen werden!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="741"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="742"/>
|
||||
<source>File has changed since discovery</source>
|
||||
<translation>Datei ist seit der Entdeckung geändert worden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="791"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="792"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation>Fehler beim Schreiben der Metadaten in die Datenbank</translation>
|
||||
</message>
|
||||
@@ -2450,18 +2450,18 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="366"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="412"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="413"/>
|
||||
<source>Public sh&aring requires a password</source>
|
||||
<translation>Öffentliches Teilen erfordert ein P&asswort</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="434"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="435"/>
|
||||
<source>Please Set Password</source>
|
||||
<translation>Bitte wählen Sie ein Passwort:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="498"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="499"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="500"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="501"/>
|
||||
<source>&Share link</source>
|
||||
<translation>&Link teilen</translation>
|
||||
</message>
|
||||
@@ -2871,12 +2871,12 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
<translation>Nur %1 sind verfügbar. Zum Beginnen werden mindestens %2 benötigt.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1134"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1139"/>
|
||||
<source>Not allowed because you don't have permission to add parent folder</source>
|
||||
<translation>Nicht erlaubt, da Sie keine Rechte zur Erstellung von Unterordnern haben</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1141"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1146"/>
|
||||
<source>Not allowed because you don't have permission to add files in that folder</source>
|
||||
<translation>Nicht erlaubt, da Sie keine Rechte zum Hinzufügen von Dateien in diesen Ordner haben</translation>
|
||||
</message>
|
||||
@@ -2981,64 +2981,64 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
<translation>Fehler beim Einlesen der Blacklist aus der lokalen Datenbank</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="787"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="791"/>
|
||||
<source>Unable to read from the sync journal.</source>
|
||||
<translation>Fehler beim Einlesen des Synchronisierungsprotokolls.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="833"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="837"/>
|
||||
<source>Cannot open the sync journal</source>
|
||||
<translation>Synchronisationsbericht kann nicht geöffnet werden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="889"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="894"/>
|
||||
<source>File name contains at least one invalid character</source>
|
||||
<translation>Der Dateiname enthält mindestens ein ungültiges Zeichen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1093"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1100"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1098"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1105"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation>Aufgrund der »Zu synchronisierende Elemente auswählen«-Sperrliste ignoriert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1119"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1124"/>
|
||||
<source>Not allowed because you don't have permission to add subfolders to that folder</source>
|
||||
<translation>Nicht erlaubt, da Sie keine Rechte zur Erstellung von Unterordnern haben</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1161"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1166"/>
|
||||
<source>Not allowed to upload this file because it is read-only on the server, restoring</source>
|
||||
<translation>Das Hochladen dieser Datei ist nicht erlaubt, da die Datei auf dem Server schreibgeschützt ist, Wiederherstellung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1178"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1198"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1183"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1203"/>
|
||||
<source>Not allowed to remove, restoring</source>
|
||||
<translation>Löschen nicht erlaubt, Wiederherstellung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1211"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1216"/>
|
||||
<source>Local files and share folder removed.</source>
|
||||
<translation>Lokale Dateien und Freigabeordner wurden entfernt.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1267"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1272"/>
|
||||
<source>Move not allowed, item restored</source>
|
||||
<translation>Verschieben nicht erlaubt, Element wiederhergestellt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1278"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1283"/>
|
||||
<source>Move not allowed because %1 is read-only</source>
|
||||
<translation>Verschieben nicht erlaubt, da %1 schreibgeschützt ist</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the destination</source>
|
||||
<translation>Das Ziel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the source</source>
|
||||
<translation>Die Quelle</translation>
|
||||
</message>
|
||||
@@ -3068,8 +3068,8 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="289"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<translation><p>Copyright ownCloud, Incorporated</p></translation>
|
||||
<source><p>Copyright ownCloud GmbH</p></source>
|
||||
<translation><p>Copyright ownCloud GmbH</p></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="290"/>
|
||||
@@ -3293,8 +3293,8 @@ Es ist nicht ratsam, diese zu benutzen.</translation>
|
||||
<name>OCC::ownCloudTheme</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="47"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Version %2. Weitere Informationen unter <a href="%3">%4</a></p><p><small>Von Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz und anderen.</small></p><p>Copyright ownCloud, Inc.</p><p>Lizensiert unter den Bedingungen der GNU General Public License (GPL) Version 2.0<br/>ownCloud und das ownCloud Logo sind eingetragene Warenzeichen der ownCloud Inc. in den USA, anderen Ländern, oder beidem.</p></translation>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud GmbH</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Version %2. Weitere Informationen unter <a href="%3">%4</a></p><p><small>Von Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz und anderen.</small></p><p>Copyright ownCloud GmbH</p><p>Lizensiert unter den Bedingungen der GNU General Public License (GPL) Version 2.0<br/>ownCloud und das ownCloud Logo sind eingetragene Warenzeichen der ownCloud Inc. in den USA, anderen Ländern, oder beidem.</p></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
+81
-81
@@ -522,9 +522,9 @@
|
||||
<context>
|
||||
<name>OCC::CleanupPollsJob</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="772"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="779"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -724,7 +724,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<message>
|
||||
<location filename="../src/gui/folder.cpp" line="1006"/>
|
||||
<source>Backup detected</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ανιχνεύθηκε αντίγραφο ασφαλείας</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folder.cpp" line="1008"/>
|
||||
@@ -860,7 +860,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusdelegate.cpp" line="241"/>
|
||||
<source>Synchronizing with local folder</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Συγχρονισμός με τοπικό φάκελο</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusdelegate.cpp" line="285"/>
|
||||
@@ -892,7 +892,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation>Σφάλμα κατά τη φόρτωση της λίστας φακέλων από το διακομιστή.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="204"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="205"/>
|
||||
<source>Signed out</source>
|
||||
<translation>Αποσύνδεση</translation>
|
||||
</message>
|
||||
@@ -902,96 +902,96 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation>Η επιλογή προσθήκης φακέλου δεν είναι διαθέσιμη καθώς συγχρονίζονται ήδη όλα τα αρχεία. Για να επιλέξετε συγχρονισμό φακέλων, αφαιρέστε τον αρχικό φάκελο που έχει ρυθμιστεί.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="169"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="170"/>
|
||||
<source>Fetching folder list from server...</source>
|
||||
<translation>Λήψη λίστας φακέλων από το διακομιστή...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="832"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="841"/>
|
||||
<source>Checking for changes in '%1'</source>
|
||||
<translation>Έλεγχος αλλαγών στο '%1'.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="867"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="876"/>
|
||||
<source>, '%1'</source>
|
||||
<extracomment>Build a list of file names</extracomment>
|
||||
<translation>, '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="870"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="879"/>
|
||||
<source>'%1'</source>
|
||||
<extracomment>Argument is a file name</extracomment>
|
||||
<translation>'%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="895"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="904"/>
|
||||
<source>Syncing %1</source>
|
||||
<extracomment>Example text: "Syncing 'foo.txt', 'bar.txt'"</extracomment>
|
||||
<translation>Συγχρονισμός %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="897"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="907"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="906"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="916"/>
|
||||
<source>, </source>
|
||||
<translation>, </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="901"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<source>download %1/s</source>
|
||||
<extracomment>Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>λήψη %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="903"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<source>u2193 %1/s</source>
|
||||
<translation>u2193 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
|
||||
<source>upload %1/s</source>
|
||||
<extracomment>Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation>μεταφόρτωση %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<source>u2191 %1/s</source>
|
||||
<translation>u2191 %1/s</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="917"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="926"/>
|
||||
<source>%1 %2 (%3 of %4)</source>
|
||||
<extracomment>Example text: "uploading foobar.png (2MB of 2MB)"</extracomment>
|
||||
<translation>%1 %2 (%3 από %4)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="930"/>
|
||||
<source>%1 %2</source>
|
||||
<extracomment>Example text: "uploading foobar.png"</extracomment>
|
||||
<translation>%1 %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="938"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="947"/>
|
||||
<source>%5 left, %1 of %2, file %3 of %4</source>
|
||||
<extracomment>Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"</extracomment>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="944"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="953"/>
|
||||
<source>file %1 of %2</source>
|
||||
<translation>αρχείο %1 από %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="984"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="993"/>
|
||||
<source>Waiting...</source>
|
||||
<translation>Αναμονή...</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="986"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="995"/>
|
||||
<source>Waiting for %n other folder(s)...</source>
|
||||
<translation><numerusform>Αναμονή για %n άλλο φάκελο...</numerusform><numerusform>Αναμονή για %n άλλους φακέλους...</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="992"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="1001"/>
|
||||
<source>Preparing to sync...</source>
|
||||
<translation>Προετοιμασία για συγχρονισμό...</translation>
|
||||
</message>
|
||||
@@ -1526,7 +1526,7 @@ Items where deletion is allowed will be deleted if they prevent a directory from
|
||||
<message>
|
||||
<location filename="../src/gui/notificationwidget.cpp" line="99"/>
|
||||
<source>Closing in a few seconds...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Κλείσιμο σε λίγα δευτερόλεπτα...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/notificationwidget.cpp" line="133"/>
|
||||
@@ -1916,9 +1916,9 @@ It is not advisable to use it.</source>
|
||||
<context>
|
||||
<name>OCC::PropagateDirectory</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="712"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="718"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1954,19 +1954,19 @@ It is not advisable to use it.</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="693"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="694"/>
|
||||
<source>File %1 cannot be saved because of a local file name clash!</source>
|
||||
<translation>Το αρχείο %1 δεν είναι δυνατό να αποθηκευτεί λόγω διένεξης με το όνομα ενός τοπικού ονόματος αρχείου!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="741"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="742"/>
|
||||
<source>File has changed since discovery</source>
|
||||
<translation>Το αρχείο έχει αλλάξει από όταν ανακαλύφθηκε</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="791"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="792"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1992,7 +1992,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatorjobs.cpp" line="155"/>
|
||||
<source>could not delete file %1, error: %2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>αδυναμία διαγραφής αρχείου %1, σφάλμα: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatorjobs.cpp" line="163"/>
|
||||
@@ -2007,7 +2007,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatorjobs.cpp" line="181"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2038,7 +2038,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatorjobs.cpp" line="245"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2064,7 +2064,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemkdir.cpp" line="148"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2092,7 +2092,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="175"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2141,7 +2141,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="800"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2184,7 +2184,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="78"/>
|
||||
<source>Local sync protocol</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Πρωτόκολλο τοπικού συγχρονισμού</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="80"/>
|
||||
@@ -2279,7 +2279,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="247"/>
|
||||
<source>An error occurred while loading the list of sub folders.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Παρουσιάστηκε σφάλμα κατά την φόρτωση της λίστας των υπο-φακέλων</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2378,7 +2378,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="101"/>
|
||||
<source>The server does not allow sharing</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διακομιστής δεν επιτρέπει τον διαμοιρασμό</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="113"/>
|
||||
@@ -2450,18 +2450,18 @@ It is not advisable to use it.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="366"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="412"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="413"/>
|
||||
<source>Public sh&aring requires a password</source>
|
||||
<translation>Ο δημόσιος &διαμοιρασμός απαιτεί κωδικό πρόσβασης</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="434"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="435"/>
|
||||
<source>Please Set Password</source>
|
||||
<translation>Παρακαλούμε ορίστε Κωδικό</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="498"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="499"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="500"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="501"/>
|
||||
<source>&Share link</source>
|
||||
<translation>Δ&ιαμοιρασμός συνδέσμου</translation>
|
||||
</message>
|
||||
@@ -2481,7 +2481,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/shareusergroupwidget.cpp" line="224"/>
|
||||
<source>No results for '%1'</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Κανένα αποτέλεσμα για '%1'</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2862,7 +2862,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="440"/>
|
||||
<source>File/Folder is ignored because it's hidden.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Το Αρχείο/ο Φάκελος αγνοήθηκε επειδή είναι κρυφό.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="701"/>
|
||||
@@ -2871,12 +2871,12 @@ It is not advisable to use it.</source>
|
||||
<translation>Μόνο %1 είναι διαθέσιμα, απαιτούνται τουλάχιστον %2 για την εκκίνηση</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1134"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1139"/>
|
||||
<source>Not allowed because you don't have permission to add parent folder</source>
|
||||
<translation>Δεν επιτρέπεται επειδή δεν έχετε δικαιώματα να προσθέσετε γονικό κατάλογο</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1141"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1146"/>
|
||||
<source>Not allowed because you don't have permission to add files in that folder</source>
|
||||
<translation>Δεν επιτρέπεται επειδή δεν έχετε δικαιώματα να προσθέσετε αρχεία σε αυτόν τον φάκελο</translation>
|
||||
</message>
|
||||
@@ -2928,7 +2928,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="188"/>
|
||||
<source>Access is forbidden</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Δεν επιτρέπεται η πρόσβαση</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="199"/>
|
||||
@@ -2978,67 +2978,67 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="754"/>
|
||||
<source>Unable to read the blacklist from the local database</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Αδυναμία ανάγνωσης της μαύρης λίστας από την τοπική βάση δεδομένων</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="787"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="791"/>
|
||||
<source>Unable to read from the sync journal.</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="833"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="837"/>
|
||||
<source>Cannot open the sync journal</source>
|
||||
<translation>Αδυναμία ανοίγματος του αρχείου συγχρονισμού</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="889"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="894"/>
|
||||
<source>File name contains at least one invalid character</source>
|
||||
<translation>Το όνομα αρχείου περιέχει έναν τουλάχιστον μη έγκυρο χαρακτήρα</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1093"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1100"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1098"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1105"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation>Αγνοήθηκε εξαιτίας της μαύρης λίστας "διάλεξε τι να συγχρονιστεί"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1119"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1124"/>
|
||||
<source>Not allowed because you don't have permission to add subfolders to that folder</source>
|
||||
<translation>Δεν επιτρέπεται επειδή δεν έχετε δικαιώματα να προσθέσετε υποφακέλους σε αυτό τον φάκελο</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1161"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1166"/>
|
||||
<source>Not allowed to upload this file because it is read-only on the server, restoring</source>
|
||||
<translation>Δεν επιτρέπεται να μεταφορτώσετε αυτό το αρχείο επειδή είναι μόνο για ανάγνωση στο διακομιστή, αποκατάσταση σε εξέλιξη</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1178"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1198"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1183"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1203"/>
|
||||
<source>Not allowed to remove, restoring</source>
|
||||
<translation>Δεν επιτρέπεται η αφαίρεση, αποκατάσταση σε εξέλιξη</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1211"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1216"/>
|
||||
<source>Local files and share folder removed.</source>
|
||||
<translation>Οι τοπικοί φάκελοι και ο φάκελος κοινής χρήσης αφαιρέθηκαν.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1267"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1272"/>
|
||||
<source>Move not allowed, item restored</source>
|
||||
<translation>Η μετακίνηση δεν επιτρέπεται, το αντικείμενο αποκαταστάθηκε</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1278"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1283"/>
|
||||
<source>Move not allowed because %1 is read-only</source>
|
||||
<translation>Η μετακίνηση δεν επιτρέπεται επειδή το %1 είναι μόνο για ανάγνωση</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the destination</source>
|
||||
<translation>ο προορισμός</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the source</source>
|
||||
<translation>η προέλευση</translation>
|
||||
</message>
|
||||
@@ -3048,7 +3048,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/synclogdialog.ui" line="14"/>
|
||||
<source>Synchronisation Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ιστορικό συγχρονισμού</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -3068,8 +3068,8 @@ It is not advisable to use it.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="289"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<translation><p>Πνευματικά δικαιώματα ownCloud, Ανώνυμη Εταιρία</p></translation>
|
||||
<source><p>Copyright ownCloud GmbH</p></source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="290"/>
|
||||
@@ -3195,7 +3195,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="236"/>
|
||||
<source>Unsupported Server Version</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Μη υποστηριζόμενη έκδοση διακομιστή</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="237"/>
|
||||
@@ -3215,37 +3215,37 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="296"/>
|
||||
<source>Account synchronization is disabled</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο λογαριασμός συγχρονισμού έχει απενεργοποιηθεί</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="379"/>
|
||||
<source>Unpause all folders</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Αναίρεση παύσης όλων των φακέλων</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="384"/>
|
||||
<source>Pause all folders</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Παύση όλων των φακέλων</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="515"/>
|
||||
<source>Unpause all synchronization</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Αναίρεση παύσης όλων των συγχρονισμών</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="517"/>
|
||||
<source>Unpause synchronization</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Αναίρεση παύσης συγχρονσμού</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="525"/>
|
||||
<source>Pause all synchronization</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Παύση όλων των συγχρονισμών</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="527"/>
|
||||
<source>Pause synchronization</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Παύση συγχρονισμού</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="534"/>
|
||||
@@ -3293,8 +3293,8 @@ It is not advisable to use it.</source>
|
||||
<name>OCC::ownCloudTheme</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="47"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation><p>Έκδοση %2. Για περισσότερες πληροφορίες επισκεφθείτε <a href="%3">%4</a></p><p><small>Των Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz και άλλων.</small></p><p>Πνευματικά δικαιώματα ownCloud, Inc.</p><p>Αδειοδότηση υπό την GNU General Public License (GPL) Έκδοση 2.0<br/>το ownCloud και το λογότυπο ownCloud είναι σήματα κατατεθέντα της ownCloud, Inc. στις Η.Π.Α., σε άλλες χώρες ή και στα δύο</p></translation>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud GmbH</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -3507,7 +3507,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/application.cpp" line="599"/>
|
||||
<source>QT_LAYOUT_DIRECTION</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>QT_LAYOUT_DIRECTION</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -3515,7 +3515,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="473"/>
|
||||
<source>in the future</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>στο μέλλον</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/libsync/utility.cpp" line="469"/>
|
||||
@@ -3530,12 +3530,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="482"/>
|
||||
<source>now</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>τώρα</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="484"/>
|
||||
<source>Less than a minute ago</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Λιγότερο από ένα λεπτό πριν</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/libsync/utility.cpp" line="487"/>
|
||||
@@ -3573,7 +3573,7 @@ It is not advisable to use it.</source>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/libsync/utility.cpp" line="319"/>
|
||||
<source>%n year(s)</source>
|
||||
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation>
|
||||
<translation><numerusform>%n χρόνος</numerusform><numerusform>%n χρόνια</numerusform></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/libsync/utility.cpp" line="320"/>
|
||||
|
||||
+46
-46
@@ -530,7 +530,7 @@
|
||||
<context>
|
||||
<name>OCC::CleanupPollsJob</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="772"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="779"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -918,7 +918,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="204"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="205"/>
|
||||
<source>Signed out</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -928,91 +928,91 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="169"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="170"/>
|
||||
<source>Fetching folder list from server...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="832"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="841"/>
|
||||
<source>Checking for changes in '%1'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="867"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="876"/>
|
||||
<source>, '%1'</source>
|
||||
<extracomment>Build a list of file names</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="870"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="879"/>
|
||||
<source>'%1'</source>
|
||||
<extracomment>Argument is a file name</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="895"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="904"/>
|
||||
<source>Syncing %1</source>
|
||||
<extracomment>Example text: "Syncing 'foo.txt', 'bar.txt'"</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="897"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="907"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="906"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="916"/>
|
||||
<source>, </source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="901"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<source>download %1/s</source>
|
||||
<extracomment>Example text: "download 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="903"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<source>u2193 %1/s</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="910"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="919"/>
|
||||
<source>upload %1/s</source>
|
||||
<extracomment>Example text: "upload 24Kb/s" (%1 is replaced by 24Kb (translated))</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="912"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<source>u2191 %1/s</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="917"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="926"/>
|
||||
<source>%1 %2 (%3 of %4)</source>
|
||||
<extracomment>Example text: "uploading foobar.png (2MB of 2MB)"</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="921"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="930"/>
|
||||
<source>%1 %2</source>
|
||||
<extracomment>Example text: "uploading foobar.png"</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="938"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="947"/>
|
||||
<source>%5 left, %1 of %2, file %3 of %4</source>
|
||||
<extracomment>Example text: "5 minutes left, 12 MB of 345 MB, file 6 of 7"</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="944"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="953"/>
|
||||
<source>file %1 of %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="984"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="993"/>
|
||||
<source>Waiting...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="986"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="995"/>
|
||||
<source>Waiting for %n other folder(s)...</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
@@ -1020,7 +1020,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="992"/>
|
||||
<location filename="../src/gui/folderstatusmodel.cpp" line="1001"/>
|
||||
<source>Preparing to sync...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -1937,7 +1937,7 @@ It is not advisable to use it.</source>
|
||||
<context>
|
||||
<name>OCC::PropagateDirectory</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="712"/>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="718"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -1975,17 +1975,17 @@ It is not advisable to use it.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="693"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="694"/>
|
||||
<source>File %1 cannot be saved because of a local file name clash!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="741"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="742"/>
|
||||
<source>File has changed since discovery</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="791"/>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="792"/>
|
||||
<source>Error writing metadata to the database</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -2471,18 +2471,18 @@ It is not advisable to use it.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="366"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="412"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="413"/>
|
||||
<source>Public sh&aring requires a password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="434"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="435"/>
|
||||
<source>Please Set Password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="498"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="499"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="500"/>
|
||||
<location filename="../src/gui/sharelinkwidget.cpp" line="501"/>
|
||||
<source>&Share link</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -2890,12 +2890,12 @@ It is not advisable to use it.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1134"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1139"/>
|
||||
<source>Not allowed because you don't have permission to add parent folder</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1141"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1146"/>
|
||||
<source>Not allowed because you don't have permission to add files in that folder</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -3000,64 +3000,64 @@ It is not advisable to use it.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="787"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="791"/>
|
||||
<source>Unable to read from the sync journal.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="833"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="837"/>
|
||||
<source>Cannot open the sync journal</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="889"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="894"/>
|
||||
<source>File name contains at least one invalid character</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1093"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1100"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1098"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1105"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1119"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1124"/>
|
||||
<source>Not allowed because you don't have permission to add subfolders to that folder</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1161"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1166"/>
|
||||
<source>Not allowed to upload this file because it is read-only on the server, restoring</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1178"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1198"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1183"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1203"/>
|
||||
<source>Not allowed to remove, restoring</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1211"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1216"/>
|
||||
<source>Local files and share folder removed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1267"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1272"/>
|
||||
<source>Move not allowed, item restored</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1278"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1283"/>
|
||||
<source>Move not allowed because %1 is read-only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the destination</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1279"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="1284"/>
|
||||
<source>the source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -3087,7 +3087,7 @@ It is not advisable to use it.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="289"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<source><p>Copyright ownCloud GmbH</p></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -3312,7 +3312,7 @@ It is not advisable to use it.</source>
|
||||
<name>OCC::ownCloudTheme</name>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="47"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud GmbH</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário