From 87a7642381858c298a3c3dbc4d3480701bf501e5 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 22 May 2017 10:10:12 +0200 Subject: [PATCH 01/64] Settings: Ensure the 'about' label isn't cut off #5760 --- src/gui/generalsettings.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/generalsettings.ui b/src/gui/generalsettings.ui index 5a035a5922..20f2c86d37 100644 --- a/src/gui/generalsettings.ui +++ b/src/gui/generalsettings.ui @@ -152,6 +152,12 @@ + + + 0 + 0 + + About From c1d2a9ab92f2c81f3be24e63a8ec0edab9dd05d4 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 22 May 2017 09:13:23 +0200 Subject: [PATCH 02/64] Sharing: Show warning that link shares are public #5785 #5747 Backport of 3872e060ba33913e43714776a1afce787e772351 --- src/gui/sharelinkwidget.ui | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/gui/sharelinkwidget.ui b/src/gui/sharelinkwidget.ui index 05809b8e26..d6bed7f9e0 100644 --- a/src/gui/sharelinkwidget.ui +++ b/src/gui/sharelinkwidget.ui @@ -37,7 +37,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -102,7 +102,7 @@ 0 - + 20 @@ -129,7 +129,7 @@ - + 0 @@ -150,7 +150,7 @@ - + @@ -180,7 +180,7 @@ - + QLayout::SetDefaultConstraint @@ -223,7 +223,7 @@ - + @@ -261,10 +261,23 @@ + + + + Anyone with the link has access to the file/folder + + + Qt::PlainText + + + true + + + - + Qt::Vertical From 3be73ad1ca00f6c635eff5a9429bfc33535d5535 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Tue, 23 May 2017 02:22:15 +0200 Subject: [PATCH 03/64] [tx-robot] updated from transifex --- mirall.desktop.in | 7 +++++++ translations/client_ca.ts | 11 ++++++++--- translations/client_cs.ts | 11 ++++++++--- translations/client_de.ts | 11 ++++++++--- translations/client_el.ts | 11 ++++++++--- translations/client_en.ts | 11 ++++++++--- translations/client_es.ts | 11 ++++++++--- translations/client_es_AR.ts | 11 ++++++++--- translations/client_et.ts | 11 ++++++++--- translations/client_eu.ts | 11 ++++++++--- translations/client_fa.ts | 11 ++++++++--- translations/client_fi.ts | 11 ++++++++--- translations/client_fr.ts | 11 ++++++++--- translations/client_gl.ts | 11 ++++++++--- translations/client_hu.ts | 11 ++++++++--- translations/client_it.ts | 11 ++++++++--- translations/client_ja.ts | 11 ++++++++--- translations/client_nb_NO.ts | 11 ++++++++--- translations/client_nl.ts | 11 ++++++++--- translations/client_pl.ts | 11 ++++++++--- translations/client_pt.ts | 11 ++++++++--- translations/client_pt_BR.ts | 11 ++++++++--- translations/client_ru.ts | 11 ++++++++--- translations/client_sk.ts | 11 ++++++++--- translations/client_sl.ts | 11 ++++++++--- translations/client_sr.ts | 11 ++++++++--- translations/client_sv.ts | 11 ++++++++--- translations/client_th.ts | 11 ++++++++--- translations/client_tr.ts | 11 ++++++++--- translations/client_uk.ts | 11 ++++++++--- translations/client_zh_CN.ts | 11 ++++++++--- translations/client_zh_TW.ts | 11 ++++++++--- 32 files changed, 255 insertions(+), 93 deletions(-) diff --git a/mirall.desktop.in b/mirall.desktop.in index 0d56e2e891..3b8e96f529 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -9,6 +9,9 @@ Icon=@APPLICATION_EXECUTABLE@ Keywords=@APPLICATION_NAME@;syncing;file;sharing; X-GNOME-Autostart-Delay=3 +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion @@ -149,6 +152,10 @@ GenericName[zh_CN]=文件夹同步 Name[zh_CN]=@APPLICATION_NAME@ 桌面同步客户端 Icon[zh_CN]=@APPLICATION_EXECUTABLE@ GenericName[zh_TW]=資料夾同步 +Comment[es_AR]=Cliente de sincronización para escritorio @APPLICATION_NAME@ +GenericName[es_AR]=Sincronización de directorio +Name[es_AR]=Cliente de sincronización para escritorio @APPLICATION_NAME@ +Icon[es_AR]=@APPLICATION_EXECUTABLE@ Comment[lt_LT]=@APPLICATION_NAME@ darbalaukio sinchronizavimo programa GenericName[lt_LT]=Katalogo sinchnorizacija Name[lt_LT]=@APPLICATION_NAME@ darbalaukio programa diff --git a/translations/client_ca.ts b/translations/client_ca.ts index ae14fb3c10..995616a9cd 100644 --- a/translations/client_ca.ts +++ b/translations/client_ca.ts @@ -1255,17 +1255,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Quant a - + Updates Actualitzacions - + &Restart && Update &Reiniciar && Actualitzar @@ -2549,6 +2549,11 @@ No és aconsellada usar-la. Allow editing Permetre edició + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_cs.ts b/translations/client_cs.ts index 7461a4e5ab..9d95dcf839 100644 --- a/translations/client_cs.ts +++ b/translations/client_cs.ts @@ -1258,17 +1258,17 @@ Pokračováním v synchronizaci způsobí přepsání všech vašich souborů st - + About O aplikaci - + Updates Aktualizace - + &Restart && Update &Restart && aktualizace @@ -2552,6 +2552,11 @@ Nedoporučuje se jí používat. Allow editing Povolit úpravy + + + Anyone with the link has access to the file/folder + Kdokoliv, kdo má odkaz, může přistupovat k tomuto souboru/složce + P&assword protect diff --git a/translations/client_de.ts b/translations/client_de.ts index 1139e88318..577cbf9af1 100644 --- a/translations/client_de.ts +++ b/translations/client_de.ts @@ -1260,17 +1260,17 @@ Wenn diese Synchronisation fortgesetzt wird, werden Dateien eventuell von älter - + About Über - + Updates Updates - + &Restart && Update &Neustarten && aktualisieren @@ -2553,6 +2553,11 @@ Es ist nicht ratsam, diese zu benutzen. Allow editing Bearbeitung erlauben + + + Anyone with the link has access to the file/folder + Jeder mit dem Link hat Zugriff auf die Datei/Ordner + P&assword protect diff --git a/translations/client_el.ts b/translations/client_el.ts index 0b2a80c493..e5dc55d155 100644 --- a/translations/client_el.ts +++ b/translations/client_el.ts @@ -1260,17 +1260,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Σχετικά - + Updates Ενημερώσεις - + &Restart && Update &Επανεκκίνηση && Ενημέρωση @@ -2554,6 +2554,11 @@ It is not advisable to use it. Allow editing Επιτρέπεται η επεξεργασία + + + Anyone with the link has access to the file/folder + Οποιοσδήποτε με τη σύνδεση έχει πρόσβαση στο αρχείο / φάκελο + P&assword protect diff --git a/translations/client_en.ts b/translations/client_en.ts index 08c2ce4638..fe8f28fe2a 100644 --- a/translations/client_en.ts +++ b/translations/client_en.ts @@ -1283,17 +1283,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About - + Updates - + &Restart && Update @@ -2573,6 +2573,11 @@ It is not advisable to use it. Allow editing + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_es.ts b/translations/client_es.ts index e503887672..2c56dd9f78 100644 --- a/translations/client_es.ts +++ b/translations/client_es.ts @@ -1260,17 +1260,17 @@ Si continua con la sincronización todos los archivos serán remplazados por su - + About Acerca de - + Updates Actualizaciones - + &Restart && Update &Reiniciar && Actualizar @@ -2553,6 +2553,11 @@ No se recomienda usarla. Allow editing Permitir edición + + + Anyone with the link has access to the file/folder + Quienquiera que posea el vínculo tendrá acceso al archivo/carpeta + P&assword protect diff --git a/translations/client_es_AR.ts b/translations/client_es_AR.ts index 1d4ded8ce0..07ce3b726b 100644 --- a/translations/client_es_AR.ts +++ b/translations/client_es_AR.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Acerca de - + Updates Actualizaciones - + &Restart && Update @@ -2541,6 +2541,11 @@ It is not advisable to use it. Allow editing + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_et.ts b/translations/client_et.ts index 7e9505063f..975d447ae1 100644 --- a/translations/client_et.ts +++ b/translations/client_et.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Info - + Updates Uuendused - + &Restart && Update &Taaskäivita && Uuenda @@ -2542,6 +2542,11 @@ Selle kasutamine pole soovitatav. Allow editing Luba muutmine + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_eu.ts b/translations/client_eu.ts index 9a9292c64b..ca20669f1f 100644 --- a/translations/client_eu.ts +++ b/translations/client_eu.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Honi buruz - + Updates Eguneraketak - + &Restart && Update Be&rrabiarazi eta Eguneratu @@ -2544,6 +2544,11 @@ Ez da gomendagarria erabltzea. Allow editing Baimendu editatzea + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_fa.ts b/translations/client_fa.ts index 7af17d9f01..b324032acf 100644 --- a/translations/client_fa.ts +++ b/translations/client_fa.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About درباره - + Updates به روز رسانی ها - + &Restart && Update @@ -2541,6 +2541,11 @@ It is not advisable to use it. Allow editing اجازه‌ی ویرایش + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_fi.ts b/translations/client_fi.ts index 41641256e7..3d612d6989 100644 --- a/translations/client_fi.ts +++ b/translations/client_fi.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Tietoja - + Updates Päivitykset - + &Restart && Update &Käynnistä uudelleen && päivitä @@ -2544,6 +2544,11 @@ Osoitteen käyttäminen ei ole suositeltavaa. Allow editing Salli muokkaus + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_fr.ts b/translations/client_fr.ts index 9fda7d3017..6f10ee234a 100644 --- a/translations/client_fr.ts +++ b/translations/client_fr.ts @@ -1261,17 +1261,17 @@ Continuer la synchronisation comme d'habitude fera en sorte que tous les fi - + About À propos - + Updates Mises à jour - + &Restart && Update &Redémarrer && Mettre à jour @@ -2555,6 +2555,11 @@ Il est déconseillé de l'utiliser. Allow editing Permettre la modification + + + Anyone with the link has access to the file/folder + Quiconque dispose du lien a accès aux fichiers/dossiers + P&assword protect diff --git a/translations/client_gl.ts b/translations/client_gl.ts index c3c15bcd45..6c7d5decaf 100644 --- a/translations/client_gl.ts +++ b/translations/client_gl.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Sobre - + Updates Actualizacións - + &Restart && Update &Reiniciar e actualizar @@ -2543,6 +2543,11 @@ Recomendámoslle que non o use. Allow editing Permitir a edición + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_hu.ts b/translations/client_hu.ts index 3794b8b4b0..cf4aaf9656 100644 --- a/translations/client_hu.ts +++ b/translations/client_hu.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Rólunk - + Updates Frissítések - + &Restart && Update Új&raindítás és frissítés @@ -2541,6 +2541,11 @@ It is not advisable to use it. Allow editing Szerkesztés engedélyezése + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_it.ts b/translations/client_it.ts index 7ffe6a9106..14152c94c9 100644 --- a/translations/client_it.ts +++ b/translations/client_it.ts @@ -1256,17 +1256,17 @@ Se continui normalmente la sincronizzazione provocherai la sovrascrittura di tut - + About Informazioni - + Updates Aggiornamenti - + &Restart && Update &Riavvia e aggiorna @@ -2549,6 +2549,11 @@ Non è consigliabile utilizzarlo. Allow editing Consenti la modifica + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_ja.ts b/translations/client_ja.ts index f014ac26b0..c39d22b2fd 100644 --- a/translations/client_ja.ts +++ b/translations/client_ja.ts @@ -1258,17 +1258,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About バージョン情報 - + Updates アップデート - + &Restart && Update 再起動してアップデート(&R) @@ -2550,6 +2550,11 @@ It is not advisable to use it. Allow editing 編集を許可 + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_nb_NO.ts b/translations/client_nb_NO.ts index b47dd8462b..f4ce7ad332 100644 --- a/translations/client_nb_NO.ts +++ b/translations/client_nb_NO.ts @@ -1259,17 +1259,17 @@ Hvis synkroniseringen fortsetter som normalt, vil alle filene dine bli overskrev - + About Om - + Updates Oppdateringer - + &Restart && Update &Omstart && Oppdater @@ -2553,6 +2553,11 @@ Det er ikke tilrådelig å bruke den. Allow editing Tillat redigering + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_nl.ts b/translations/client_nl.ts index 36082de3a2..59f47d6393 100644 --- a/translations/client_nl.ts +++ b/translations/client_nl.ts @@ -1260,17 +1260,17 @@ Doorgaan met deze synchronisatie overschrijft al uw bestanden door een eerdere v - + About Over - + Updates Updates - + &Restart && Update &Herstarten en &Bijwerken @@ -2558,6 +2558,11 @@ We adviseren deze site niet te gebruiken. Allow editing Toestaan bewerken + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_pl.ts b/translations/client_pl.ts index 7744aa861d..03e3298fd2 100644 --- a/translations/client_pl.ts +++ b/translations/client_pl.ts @@ -1253,17 +1253,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About O aplikacji - + Updates Aktualizacje - + &Restart && Update &Zrestartuj && Aktualizuj @@ -2547,6 +2547,11 @@ Niezalecane jest jego użycie. Allow editing Pozwól na edycję + + + Anyone with the link has access to the file/folder + Każdy posiadający link ma dostęp do pliku/katalogu. + P&assword protect diff --git a/translations/client_pt.ts b/translations/client_pt.ts index 4cc868d776..a5cb63237d 100644 --- a/translations/client_pt.ts +++ b/translations/client_pt.ts @@ -1260,17 +1260,17 @@ Continuando a sincronização fará com que todos os seus ficheiros sejam substi - + About Sobre - + Updates Atualizações - + &Restart && Update &Reiniciar e Atualizar @@ -2554,6 +2554,11 @@ Não é aconselhada a sua utilização. Allow editing Permitir edição + + + Anyone with the link has access to the file/folder + Qualquer pessoa com a hiperligação terá acesso ao ficheiro/pasta + P&assword protect diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index 52864f4aeb..ed0931c3bf 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -1258,17 +1258,17 @@ Continuar a sincronização como normal fará com que todos os seus arquivos sej - + About Sobre - + Updates Atualizações - + &Restart && Update &Reiniciar && Atualização @@ -2551,6 +2551,11 @@ It is not advisable to use it. Allow editing Permitir edição + + + Anyone with the link has access to the file/folder + Qualquer pessoa com o link tem acesso ao arquivo/pasta + P&assword protect diff --git a/translations/client_ru.ts b/translations/client_ru.ts index 485ac8dfac..bb592ce967 100644 --- a/translations/client_ru.ts +++ b/translations/client_ru.ts @@ -1258,17 +1258,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About О программе - + Updates Обновления - + &Restart && Update &Перезапуск и обновление @@ -2551,6 +2551,11 @@ It is not advisable to use it. Allow editing Разрешить редактирование + + + Anyone with the link has access to the file/folder + Каждый, у кого есть эта ссылка, имеет доступ к файлу/каталогу + P&assword protect diff --git a/translations/client_sk.ts b/translations/client_sk.ts index 736b1fce2a..b6588e0ec3 100644 --- a/translations/client_sk.ts +++ b/translations/client_sk.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About O - + Updates Aktualizácie - + &Restart && Update &Restart && aktualizácia @@ -2543,6 +2543,11 @@ Nie je vhodné ju používať. Allow editing Povoliť úpravy + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_sl.ts b/translations/client_sl.ts index 46da52970a..6105b746a2 100644 --- a/translations/client_sl.ts +++ b/translations/client_sl.ts @@ -1260,17 +1260,17 @@ Z nadaljevanjem usklajevanja bodo vse trenutne datoteke prepisane s starejšimi - + About O programu... - + Updates Posodobitve - + &Restart && Update &Ponovno zaženi && posodobi @@ -2554,6 +2554,11 @@ Uporaba ni priporočljiva. Allow editing Dovoli urejanje + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_sr.ts b/translations/client_sr.ts index e769bac05f..addfcd255c 100644 --- a/translations/client_sr.ts +++ b/translations/client_sr.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About О програму - + Updates Ажурирања - + &Restart && Update &Поново покрени и ажурирај @@ -2543,6 +2543,11 @@ It is not advisable to use it. Allow editing уређивање + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_sv.ts b/translations/client_sv.ts index a8fdd3a0d4..86cc98f768 100644 --- a/translations/client_sv.ts +++ b/translations/client_sv.ts @@ -1253,17 +1253,17 @@ Om du fortsätter synkningen kommer alla dina filer återställas med en äldre - + About Om - + Updates Uppdateringar - + &Restart && Update %Starta om && Uppdatera @@ -2547,6 +2547,11 @@ Det är inte lämpligt använda den. Allow editing Tillåt redigering + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_th.ts b/translations/client_th.ts index f208b64901..4e31f545bf 100644 --- a/translations/client_th.ts +++ b/translations/client_th.ts @@ -1262,17 +1262,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About เกี่ยวกับเรา - + Updates อัพเดท - + &Restart && Update และเริ่มต้นใหม่ && อัพเดท @@ -2555,6 +2555,11 @@ It is not advisable to use it. Allow editing อนุญาตให้แก้ไข + + + Anyone with the link has access to the file/folder + ทุกคนที่มีลิงก์สามารถเข้าถึงไฟล์หรือโฟลเดอร์ได้ + P&assword protect diff --git a/translations/client_tr.ts b/translations/client_tr.ts index 0ff1ef5e7c..474583066d 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Hakkında - + Updates Güncellemeler - + &Restart && Update &Yeniden Başlat ve Güncelle @@ -2544,6 +2544,11 @@ Kullanmanız önerilmez. Allow editing Düzenlemeye izin ver + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_uk.ts b/translations/client_uk.ts index 5d45d854fb..046aaa15bb 100644 --- a/translations/client_uk.ts +++ b/translations/client_uk.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About Про - + Updates Оновлення - + &Restart && Update &Перезавантаження && Оновлення @@ -2542,6 +2542,11 @@ It is not advisable to use it. Allow editing Дозволити редагування + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_zh_CN.ts b/translations/client_zh_CN.ts index 95abd501e2..67de8c67ca 100644 --- a/translations/client_zh_CN.ts +++ b/translations/client_zh_CN.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About 关于 - + Updates 更新 - + &Restart && Update 重启并更新 (&R) @@ -2544,6 +2544,11 @@ It is not advisable to use it. Allow editing 允许编辑 + + + Anyone with the link has access to the file/folder + + P&assword protect diff --git a/translations/client_zh_TW.ts b/translations/client_zh_TW.ts index 5d4863008a..134f4bb717 100644 --- a/translations/client_zh_TW.ts +++ b/translations/client_zh_TW.ts @@ -1251,17 +1251,17 @@ Continuing the sync as normal will cause all your files to be overwritten by an - + About 關於 - + Updates 更新 - + &Restart && Update 重新啟動並更新 (&R) @@ -2545,6 +2545,11 @@ It is not advisable to use it. Allow editing 允許編輯 + + + Anyone with the link has access to the file/folder + + P&assword protect From a48785ee5eca7e895acbc24e1f1ea8b8a7330c7e Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 24 May 2017 02:22:16 +0200 Subject: [PATCH 04/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 3b8e96f529..b508162ace 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -12,6 +12,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 56de50de2867fb34ea3d0aab4fd217da38937730 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Thu, 25 May 2017 02:22:08 +0200 Subject: [PATCH 05/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index b508162ace..073f33525c 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -15,6 +15,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 577a2715bde1e958fb1ee78041c42581d6a5ee11 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 29 May 2017 12:05:22 +0200 Subject: [PATCH 06/64] Download: Retrigger folder discovery on 404 See owncloud/enterprise#1966 If the server and the client's database go out of sync, there could be persistent 404 errors. This change ensures that the problem corrects itself eventually by triggering a remote discovery of the file's parent folders. It does not address the root cause that might have lead to the divergence. --- src/libsync/propagatedownload.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index e87e3d45bf..0ad605dc84 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -500,6 +500,11 @@ void PropagateDownloadFile::slotGetFinished() } else if (fileNotFound) { job->setErrorString(tr("File was deleted from server")); job->setErrorStatus(SyncFileItem::SoftError); + + // As a precaution against bugs that cause our database and the + // reality on the server to diverge, rediscover this folder on the + // next sync run. + propagator()->_journal->avoidReadFromDbOnNextSync(_item->_file); } SyncFileItem::Status status = job->errorStatus(); From 78dede2ac4468d5fc9bae79f57a49d591c3782fc Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Fri, 26 May 2017 13:24:54 +0200 Subject: [PATCH 07/64] Fix build on Debian 7 (CMake pre 2.8.12) --- cmake/modules/FindQt5Keychain.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindQt5Keychain.cmake b/cmake/modules/FindQt5Keychain.cmake index 6848763fe7..4aff32d6fb 100644 --- a/cmake/modules/FindQt5Keychain.cmake +++ b/cmake/modules/FindQt5Keychain.cmake @@ -13,7 +13,9 @@ # so that it doesn't pull a different Qt version. For that reason # first look in the Qt lib directory for QtKeychain. get_target_property(_QTCORE_LIB_PATH Qt5::Core IMPORTED_LOCATION_RELEASE) -get_filename_component(QT_LIB_DIR "${_QTCORE_LIB_PATH}" DIRECTORY) + +# Use PATH here because Debian 7.0 has CMake 2.8.9 and DIRECTORY is only available from 2.8.12+ +get_filename_component(QT_LIB_DIR "${_QTCORE_LIB_PATH}" PATH) find_path(QTKEYCHAIN_INCLUDE_DIR NAMES From 0fc3df45ceeb4b3677a9b359e1810c254516dded Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Fri, 26 May 2017 13:25:43 +0200 Subject: [PATCH 08/64] Remove obsolete FindQtKeychain for Qt4 --- cmake/modules/FindQtKeychain.cmake | 39 ------------------------------ 1 file changed, 39 deletions(-) delete mode 100644 cmake/modules/FindQtKeychain.cmake diff --git a/cmake/modules/FindQtKeychain.cmake b/cmake/modules/FindQtKeychain.cmake deleted file mode 100644 index 6ef1cf7eb2..0000000000 --- a/cmake/modules/FindQtKeychain.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# (c) 2014 Copyright ownCloud GmbH -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING* file. - -# - Try to find QtKeychain -# Once done this will define -# QTKEYCHAIN_FOUND - System has QtKeychain -# QTKEYCHAIN_INCLUDE_DIRS - The QtKeychain include directories -# QTKEYCHAIN_LIBRARIES - The libraries needed to use QtKeychain -# QTKEYCHAIN_DEFINITIONS - Compiler switches required for using LibXml2 - -find_path(QTKEYCHAIN_INCLUDE_DIR - NAMES - keychain.h - PATH_SUFFIXES - qtkeychain - ) - - -find_library(QTKEYCHAIN_LIBRARY - NAMES - qtkeychain - libqtkeychain - PATHS - /usr/lib - /usr/lib/${CMAKE_ARCH_TRIPLET} - /usr/local/lib - /opt/local/lib - ${CMAKE_LIBRARY_PATH} - ${CMAKE_INSTALL_PREFIX}/lib - ) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set QTKEYCHAIN_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(QtKeychain DEFAULT_MSG - QTKEYCHAIN_LIBRARY QTKEYCHAIN_INCLUDE_DIR) - -mark_as_advanced(QTKEYCHAIN_INCLUDE_DIR QTKEYCHAIN_LIBRARY) From 42751f87d922939f7ebf502b25d6ca70dd814f35 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 22 May 2017 17:54:57 +0200 Subject: [PATCH 09/64] Application: debug implies logdebug --- src/gui/application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 4991aac56c..cba117ebba 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -438,6 +438,7 @@ void Application::parseOptions(const QStringList &options) showHint("Path for confdir not specified"); } } else if (option == QLatin1String("--debug")) { + _logDebug = true; _debugMode = true; } else if (option == QLatin1String("--version")) { _versionOnly = true; From 61d05fa4d7c06e1b6712fe7f1d4081b33cb0cbf0 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 31 May 2017 02:22:17 +0200 Subject: [PATCH 10/64] [tx-robot] updated from transifex --- translations/client_ca.ts | 10 +++++----- translations/client_cs.ts | 10 +++++----- translations/client_de.ts | 10 +++++----- translations/client_el.ts | 10 +++++----- translations/client_en.ts | 10 +++++----- translations/client_es.ts | 10 +++++----- translations/client_es_AR.ts | 10 +++++----- translations/client_et.ts | 10 +++++----- translations/client_eu.ts | 10 +++++----- translations/client_fa.ts | 10 +++++----- translations/client_fi.ts | 10 +++++----- translations/client_fr.ts | 10 +++++----- translations/client_gl.ts | 10 +++++----- translations/client_hu.ts | 10 +++++----- translations/client_it.ts | 10 +++++----- translations/client_ja.ts | 10 +++++----- translations/client_nb_NO.ts | 10 +++++----- translations/client_nl.ts | 12 ++++++------ translations/client_pl.ts | 10 +++++----- translations/client_pt.ts | 10 +++++----- translations/client_pt_BR.ts | 10 +++++----- translations/client_ru.ts | 10 +++++----- translations/client_sk.ts | 10 +++++----- translations/client_sl.ts | 10 +++++----- translations/client_sr.ts | 10 +++++----- translations/client_sv.ts | 10 +++++----- translations/client_th.ts | 10 +++++----- translations/client_tr.ts | 10 +++++----- translations/client_uk.ts | 10 +++++----- translations/client_zh_CN.ts | 24 ++++++++++++------------ translations/client_zh_TW.ts | 10 +++++----- 31 files changed, 163 insertions(+), 163 deletions(-) diff --git a/translations/client_ca.ts b/translations/client_ca.ts index 995616a9cd..4262da544d 100644 --- a/translations/client_ca.ts +++ b/translations/client_ca.ts @@ -2018,27 +2018,27 @@ No és aconsellada usar-la. El fitxer s'ha esborrat del servidor - + The file could not be downloaded completely. No es pot descarregar el fitxer completament. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery El fitxer ha canviat des de que es va descobrir - + Error writing metadata to the database Error en escriure les metadades a la base de dades diff --git a/translations/client_cs.ts b/translations/client_cs.ts index 9d95dcf839..a7e5c0de86 100644 --- a/translations/client_cs.ts +++ b/translations/client_cs.ts @@ -2021,27 +2021,27 @@ Nedoporučuje se jí používat. Soubor byl smazán ze serveru - + The file could not be downloaded completely. Soubor nemohl být kompletně stažen. - + The downloaded file is empty despite the server announced it should have been %1. Stažený soubor je prázdný, přestože server oznámil, že měl být %1. - + File %1 cannot be saved because of a local file name clash! Soubor %1 nemohl být uložen z důvodu kolize názvu se souborem v místním systému! - + File has changed since discovery Soubor se mezitím změnil - + Error writing metadata to the database Chyba zápisu metadat do databáze diff --git a/translations/client_de.ts b/translations/client_de.ts index 577cbf9af1..9406716cbd 100644 --- a/translations/client_de.ts +++ b/translations/client_de.ts @@ -2022,27 +2022,27 @@ Es ist nicht ratsam, diese zu benutzen. Die Datei wurde vom Server gelöscht - + The file could not be downloaded completely. Die Datei konnte nicht vollständig herunter geladen werden. - + The downloaded file is empty despite the server announced it should have been %1. Die heruntergeladene Datei ist leer, obwohl der Server %1 als Größe übermittelt hat. - + File %1 cannot be saved because of a local file name clash! Die Datei %1 kann aufgrund eines Konfliktes mit dem lokalen Dateinamen nicht gespeichert geladen werden! - + File has changed since discovery Datei ist seit der Entdeckung geändert worden - + Error writing metadata to the database Fehler beim Schreiben der Metadaten in die Datenbank diff --git a/translations/client_el.ts b/translations/client_el.ts index e5dc55d155..9747282ec1 100644 --- a/translations/client_el.ts +++ b/translations/client_el.ts @@ -2023,27 +2023,27 @@ It is not advisable to use it. Το αρχείο διαγράφηκε από τον διακομιστή - + The file could not be downloaded completely. Η λήψη του αρχείου δεν ολοκληρώθηκε. - + The downloaded file is empty despite the server announced it should have been %1. Το ληφθέν αρχείο είναι άδειο, παρόλο που ο διακομιστής ανακοίνωσε ότι θα έπρεπε να ήταν% 1. - + File %1 cannot be saved because of a local file name clash! Το αρχείο %1 δεν είναι δυνατό να αποθηκευτεί λόγω διένεξης με το όνομα ενός τοπικού ονόματος αρχείου! - + File has changed since discovery Το αρχείο έχει αλλάξει από όταν ανακαλύφθηκε - + Error writing metadata to the database Σφάλμα εγγραφής μεταδεδομένων στην βάση δεδομένων diff --git a/translations/client_en.ts b/translations/client_en.ts index fe8f28fe2a..e2646f23c3 100644 --- a/translations/client_en.ts +++ b/translations/client_en.ts @@ -2042,27 +2042,27 @@ It is not advisable to use it. - + The file could not be downloaded completely. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database diff --git a/translations/client_es.ts b/translations/client_es.ts index 2c56dd9f78..f696e4fd25 100644 --- a/translations/client_es.ts +++ b/translations/client_es.ts @@ -2022,27 +2022,27 @@ No se recomienda usarla. Se ha eliminado el archivo del servidor - + The file could not be downloaded completely. No se ha podido descargar el archivo completamente. - + The downloaded file is empty despite the server announced it should have been %1. El archivo descargado está vacio aunque el servidor dice que deberia haber sido %1. - + File %1 cannot be saved because of a local file name clash! ¡El fichero %1 no puede guardarse debido a un conflicto con el nombre de otro fichero local! - + File has changed since discovery El archivo ha cambiado desde que fue descubierto - + Error writing metadata to the database Error al escribir los metadatos en la base de datos diff --git a/translations/client_es_AR.ts b/translations/client_es_AR.ts index 07ce3b726b..98256d9e92 100644 --- a/translations/client_es_AR.ts +++ b/translations/client_es_AR.ts @@ -2010,27 +2010,27 @@ It is not advisable to use it. - + The file could not be downloaded completely. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database diff --git a/translations/client_et.ts b/translations/client_et.ts index 975d447ae1..7d695e17ad 100644 --- a/translations/client_et.ts +++ b/translations/client_et.ts @@ -2011,27 +2011,27 @@ Selle kasutamine pole soovitatav. Fail on serverist kustutatud - + The file could not be downloaded completely. Faili täielik allalaadimine ebaõnnestus. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! Faili %1 ei saa salvestada kuna on nime konflikt kohaliku failiga! - + File has changed since discovery Faili on pärast avastamist muudetud - + Error writing metadata to the database diff --git a/translations/client_eu.ts b/translations/client_eu.ts index ca20669f1f..53cedf8ed8 100644 --- a/translations/client_eu.ts +++ b/translations/client_eu.ts @@ -2013,27 +2013,27 @@ Ez da gomendagarria erabltzea. Fitxategia zerbitzaritik ezabatua izan da - + The file could not be downloaded completely. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database diff --git a/translations/client_fa.ts b/translations/client_fa.ts index b324032acf..53fba3ebc6 100644 --- a/translations/client_fa.ts +++ b/translations/client_fa.ts @@ -2010,27 +2010,27 @@ It is not advisable to use it. فایل از روی سرور حذف شد - + The file could not be downloaded completely. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database diff --git a/translations/client_fi.ts b/translations/client_fi.ts index 3d612d6989..ca263a3fcc 100644 --- a/translations/client_fi.ts +++ b/translations/client_fi.ts @@ -2013,27 +2013,27 @@ Osoitteen käyttäminen ei ole suositeltavaa. Tiedosto poistettiin palvelimelta - + The file could not be downloaded completely. Tiedostoa ei voitu ladata täysin. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery Tiedosto on muuttunut löytymisen jälkeen - + Error writing metadata to the database Virhe kirjoittaessa metadataa tietokantaan diff --git a/translations/client_fr.ts b/translations/client_fr.ts index 6f10ee234a..a9e38307c8 100644 --- a/translations/client_fr.ts +++ b/translations/client_fr.ts @@ -2024,27 +2024,27 @@ Il est déconseillé de l'utiliser. Le fichier a été supprimé du serveur - + The file could not be downloaded completely. Le fichier n'a pas pu être téléchargé intégralement. - + The downloaded file is empty despite the server announced it should have been %1. Le fichier téléchargé est vide bien que le serveur indique que sa taille devrait être de %1. - + File %1 cannot be saved because of a local file name clash! Le fichier %1 n'a pas pu être sauvegardé en raison d'un conflit sur le nom du fichier local ! - + File has changed since discovery Le fichier a changé depuis sa découverte - + Error writing metadata to the database Erreur à l'écriture des métadonnées dans la base de données diff --git a/translations/client_gl.ts b/translations/client_gl.ts index 6c7d5decaf..07ddb5b8a8 100644 --- a/translations/client_gl.ts +++ b/translations/client_gl.ts @@ -2012,27 +2012,27 @@ Recomendámoslle que non o use. O ficheiro vai seren eliminado do servidor - + The file could not be downloaded completely. Non foi posíbel descargar completamente o ficheiro. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! Non foi posíbel gardar o ficheiro %1 por mor dunha colisión co nome dun ficheiro local! - + File has changed since discovery O ficheiro cambiou após seren atopado - + Error writing metadata to the database diff --git a/translations/client_hu.ts b/translations/client_hu.ts index cf4aaf9656..8972b28a6f 100644 --- a/translations/client_hu.ts +++ b/translations/client_hu.ts @@ -2010,27 +2010,27 @@ It is not advisable to use it. A fájl törlésre került a szerverről - + The file could not be downloaded completely. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database diff --git a/translations/client_it.ts b/translations/client_it.ts index 14152c94c9..e2b34113d8 100644 --- a/translations/client_it.ts +++ b/translations/client_it.ts @@ -2018,27 +2018,27 @@ Non è consigliabile utilizzarlo. Il file è stato eliminato dal server - + The file could not be downloaded completely. Il file non può essere scaricato completamente. - + The downloaded file is empty despite the server announced it should have been %1. Il file scaricato è vuoto nonostante il server indicasse una dimensione di %1. - + File %1 cannot be saved because of a local file name clash! Il file %1 non può essere salvato a causa di un conflitto con un file locale. - + File has changed since discovery Il file è stato modificato dal suo rilevamento - + Error writing metadata to the database Errore durante la scrittura dei metadati nel database diff --git a/translations/client_ja.ts b/translations/client_ja.ts index c39d22b2fd..119b9ccfda 100644 --- a/translations/client_ja.ts +++ b/translations/client_ja.ts @@ -2019,27 +2019,27 @@ It is not advisable to use it. ファイルはサーバーから削除されました - + The file could not be downloaded completely. このファイルのダウンロードは完了しませんでした - + The downloaded file is empty despite the server announced it should have been %1. サーバーが通知しているファイルは %1 であるべきですが、ダウンロードファイルは空でした。 - + File %1 cannot be saved because of a local file name clash! %1 はローカルファイル名が衝突しているため保存できません! - + File has changed since discovery ファイルは発見以降に変更されました - + Error writing metadata to the database メタデータのデータベースへの書き込みに失敗 diff --git a/translations/client_nb_NO.ts b/translations/client_nb_NO.ts index f4ce7ad332..fb7e485e6a 100644 --- a/translations/client_nb_NO.ts +++ b/translations/client_nb_NO.ts @@ -2022,27 +2022,27 @@ Det er ikke tilrådelig å bruke den. Filen ble slettet fra serveren - + The file could not be downloaded completely. Hele filen kunne ikke lastes ned. - + The downloaded file is empty despite the server announced it should have been %1. Nedlastet fil er tom, selv om serveren annonserte at den skulle være %1. - + File %1 cannot be saved because of a local file name clash! Fil %1 kan ikke lagres på grunn av lokal konflikt med filnavn. - + File has changed since discovery Filen er endret siden den ble oppdaget - + Error writing metadata to the database Feil ved skriving av metadata til databasen diff --git a/translations/client_nl.ts b/translations/client_nl.ts index 59f47d6393..16dbaf1a46 100644 --- a/translations/client_nl.ts +++ b/translations/client_nl.ts @@ -2027,27 +2027,27 @@ We adviseren deze site niet te gebruiken. Bestand was verwijderd van de server - + The file could not be downloaded completely. Het bestand kon niet volledig worden gedownload. - + The downloaded file is empty despite the server announced it should have been %1. Het gedownloade bestand is leeg, hoewel de server meldde dat het %1 zou moeten zijn. - + File %1 cannot be saved because of a local file name clash! Bestand %1 kan niet worden opgeslagen wegens een lokaal bestandsnaam conflict! - + File has changed since discovery Het bestand is gewijzigd sinds het is gevonden - + Error writing metadata to the database Fout bij schrijven van Metadata naar de database @@ -2561,7 +2561,7 @@ We adviseren deze site niet te gebruiken. Anyone with the link has access to the file/folder - + Iedereen met de link heeft toegang tot het bestand of de map diff --git a/translations/client_pl.ts b/translations/client_pl.ts index 03e3298fd2..f0845f7571 100644 --- a/translations/client_pl.ts +++ b/translations/client_pl.ts @@ -2016,27 +2016,27 @@ Niezalecane jest jego użycie. Plik został usunięty z serwera - + The file could not be downloaded completely. Ten plik nie mógł być całkowicie pobrany. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! - + File has changed since discovery - + Error writing metadata to the database Błąd podczas zapisu metadanych do bazy diff --git a/translations/client_pt.ts b/translations/client_pt.ts index a5cb63237d..f3eb3ec897 100644 --- a/translations/client_pt.ts +++ b/translations/client_pt.ts @@ -2023,27 +2023,27 @@ Não é aconselhada a sua utilização. O ficheiro foi eliminado do servidor - + The file could not be downloaded completely. Não foi possível transferir o ficheiro na totalidade. - + The downloaded file is empty despite the server announced it should have been %1. O ficheiro transferido está vazio, apesar do servidor indicar que este deveria ter %1. - + File %1 cannot be saved because of a local file name clash! Ficheiro %1 não pode ser guardado devido à existência de um ficheiro local com o mesmo nome. - + File has changed since discovery O ficheiro alterou-se desde a sua descoberta - + Error writing metadata to the database Erro ao gravar os metadados para a base de dados diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index ed0931c3bf..9c6c86815a 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -2020,27 +2020,27 @@ It is not advisable to use it. O arquivo foi eliminado do servidor - + The file could not be downloaded completely. O arquivo não pode ser baixado completamente. - + The downloaded file is empty despite the server announced it should have been %1. O arquivo baixado está vazio apesar do servidor anunciou que deveria ter %1. - + File %1 cannot be saved because of a local file name clash! O arquivo %1 não pode ser salvo devido a um confronto com um nome de arquivo local! - + File has changed since discovery Arquivo foi alterado desde a descoberta - + Error writing metadata to the database Ocorreu um erro ao escrever metadados ao banco de dados diff --git a/translations/client_ru.ts b/translations/client_ru.ts index bb592ce967..2587ed5cd1 100644 --- a/translations/client_ru.ts +++ b/translations/client_ru.ts @@ -2020,27 +2020,27 @@ It is not advisable to use it. Файл был удален с сервера - + The file could not be downloaded completely. Невозможно полностью загрузить файл. - + The downloaded file is empty despite the server announced it should have been %1. Скачанный файл пуст, хотя сервер заявил, что он должен быть %1. - + File %1 cannot be saved because of a local file name clash! Файл %1 не может быть сохранён из-за локального конфликта имен! - + File has changed since discovery После обнаружения файл был изменен - + Error writing metadata to the database Ошибка записи метаданных в базу данных diff --git a/translations/client_sk.ts b/translations/client_sk.ts index b6588e0ec3..94b0ec7e16 100644 --- a/translations/client_sk.ts +++ b/translations/client_sk.ts @@ -2012,27 +2012,27 @@ Nie je vhodné ju používať. Súbor bol vymazaný zo servera - + The file could not be downloaded completely. Súbor sa nedá stiahnuť úplne. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! Súbor %1 nie je možné uložiť, pretože jeho názov koliduje s názvom lokálneho súboru! - + File has changed since discovery Súbor sa medzitým zmenil - + Error writing metadata to the database Chyba pri zápise metadát do databázy diff --git a/translations/client_sl.ts b/translations/client_sl.ts index 6105b746a2..cf5c03f5b2 100644 --- a/translations/client_sl.ts +++ b/translations/client_sl.ts @@ -2023,27 +2023,27 @@ Uporaba ni priporočljiva. Datoteka je izbrisana s strežnika - + The file could not be downloaded completely. Datoteke ni mogoče prejeti v celoti. - + The downloaded file is empty despite the server announced it should have been %1. Prejeta datoteka je prazna, čeprav je na strežniku velikosti %1. - + File %1 cannot be saved because of a local file name clash! Datoteke %1 ni mogoče shraniti zaradi neskladja z imenom obstoječe datoteke! - + File has changed since discovery Datoteka je bila spremenjena po usklajevanju seznama datotek - + Error writing metadata to the database Napaka zapisovanja metapodatkov v podatkovno zbirko diff --git a/translations/client_sr.ts b/translations/client_sr.ts index addfcd255c..8a6b33955a 100644 --- a/translations/client_sr.ts +++ b/translations/client_sr.ts @@ -2012,27 +2012,27 @@ It is not advisable to use it. Фајл је обрисан са сервера - + The file could not be downloaded completely. Фајл није могао бити преузет у потпуности. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! Фајл %1 се не може сачувати јер се судара са називом локалног фајла! - + File has changed since discovery Фајл је измењен у међувремену - + Error writing metadata to the database diff --git a/translations/client_sv.ts b/translations/client_sv.ts index 86cc98f768..d66808970a 100644 --- a/translations/client_sv.ts +++ b/translations/client_sv.ts @@ -2016,27 +2016,27 @@ Det är inte lämpligt använda den. Filen har tagits bort från servern - + The file could not be downloaded completely. Filen kunde inte laddas ner fullständigt. - + The downloaded file is empty despite the server announced it should have been %1. Den nedladdade filen är tom men servern sa att den skulle vara %1. - + File %1 cannot be saved because of a local file name clash! Fil %1 kan inte sparas eftersom namnet krockar med en lokal fil! - + File has changed since discovery Filen har ändrats sedan upptäckten - + Error writing metadata to the database Fel vid skrivning av metadata till databasen diff --git a/translations/client_th.ts b/translations/client_th.ts index 4e31f545bf..fa56f79241 100644 --- a/translations/client_th.ts +++ b/translations/client_th.ts @@ -2024,27 +2024,27 @@ It is not advisable to use it. ไฟล์ถูกลบออกจากเซิร์ฟเวอร์ - + The file could not be downloaded completely. ดาวน์โหลดไฟล์ไม่สำเร็จ - + The downloaded file is empty despite the server announced it should have been %1. ไฟล์ที่ดาวน์โหลดว่างเปล่าแม้ว่าเซิร์ฟเวอร์ประกาศว่าควรจะเป็น %1 - + File %1 cannot be saved because of a local file name clash! ไฟล์ %1 ไม่สามารถบันทึกได้เพราะชื่อไฟล์ต้นทางเหมือนกัน! - + File has changed since discovery ไฟล์มีการเปลี่ยนแปลงตั้งแต่ถูกพบ - + Error writing metadata to the database ข้อผิดพลาดในการเขียนข้อมูลเมตาไปยังฐานข้อมูล diff --git a/translations/client_tr.ts b/translations/client_tr.ts index 474583066d..43c97aff0a 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -2013,27 +2013,27 @@ Kullanmanız önerilmez. Dosya sunucudan silindi - + The file could not be downloaded completely. Dosya tamamıyla indirilemedi. - + The downloaded file is empty despite the server announced it should have been %1. Sunucu boyutunu %1 olarak duyurmasına rağmen indirilen dosya boş. - + File %1 cannot be saved because of a local file name clash! Yerel bir dosya ismi ile çakıştığından, %1 dosyası kaydedilemedi! - + File has changed since discovery Dosya, bulunduğundan itibaren değişmiş - + Error writing metadata to the database Veritabanına üstveri yazma hatası diff --git a/translations/client_uk.ts b/translations/client_uk.ts index 046aaa15bb..a215d27341 100644 --- a/translations/client_uk.ts +++ b/translations/client_uk.ts @@ -2011,27 +2011,27 @@ It is not advisable to use it. Файл видалено з сервера - + The file could not be downloaded completely. Файл не може бути завантажений повністю. - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! Файл %1 не збережено через локальний конфлікт назви файлу! - + File has changed since discovery Файл змінився з моменту знаходження - + Error writing metadata to the database diff --git a/translations/client_zh_CN.ts b/translations/client_zh_CN.ts index 67de8c67ca..356ced7f28 100644 --- a/translations/client_zh_CN.ts +++ b/translations/client_zh_CN.ts @@ -163,12 +163,12 @@ Force sync now - + 强制同步 Restart sync - + 重新开始同步 @@ -536,7 +536,7 @@ Error accessing the configuration file - + 访问配置文件时发生错误 @@ -546,7 +546,7 @@ Quit ownCloud - + 退出 ownCloud @@ -2013,27 +2013,27 @@ It is not advisable to use it. 已从服务器删除文件 - + The file could not be downloaded completely. 文件无法完整下载。 - + The downloaded file is empty despite the server announced it should have been %1. 虽然服务器宣称已完成 %1,但实际下载文件为空。 - + File %1 cannot be saved because of a local file name clash! 由于本地文件名冲突,文件 %1 无法保存。 - + File has changed since discovery 自从发现文件以来,它已经被改变了 - + Error writing metadata to the database 向数据库写入元数据错误 @@ -2578,7 +2578,7 @@ It is not advisable to use it. Could not open email client - + 无法打开邮件客户端 @@ -3079,7 +3079,7 @@ It is not advisable to use it. File names containing the character '%1' are not supported on this file system. - + 此文件系统不支持包含字符 '%1' 的文件名。 @@ -3089,7 +3089,7 @@ It is not advisable to use it. Filename contains trailing spaces. - + 文件名尾部含有空格 diff --git a/translations/client_zh_TW.ts b/translations/client_zh_TW.ts index 134f4bb717..5c67ec5320 100644 --- a/translations/client_zh_TW.ts +++ b/translations/client_zh_TW.ts @@ -2014,27 +2014,27 @@ It is not advisable to use it. 檔案已從伺服器被刪除 - + The file could not be downloaded completely. 檔案下載無法完成。 - + The downloaded file is empty despite the server announced it should have been %1. - + File %1 cannot be saved because of a local file name clash! 檔案 %1 無法存檔,因為本地端的檔案名稱已毀損! - + File has changed since discovery 尋找的過程中檔案已經被更改 - + Error writing metadata to the database 寫入後設資料(metadata) 時發生錯誤 From b7fa50be4c8f84f78bd9c3e6912df91897fc9442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 27 Mar 2017 11:12:28 +0200 Subject: [PATCH 11/64] Set proper application name, icon name for freedesktop notifications Use application name defined in OEM build configuration --- CMakeLists.txt | 4 ++++ OWNCLOUD.cmake | 1 + config.h.in | 1 + src/gui/CMakeLists.txt | 18 ++++++++---------- src/gui/systray.cpp | 5 +++-- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20a0de8be7..978b353478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,10 @@ endif() find_package(ZLIB) +if (NOT DEFINED APPLICATION_ICON_NAME) + set(APPLICATION_ICON_NAME ${APPLICATION_SHORTNAME}) +endif() + configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) configure_file(test/test_journal.db "${CMAKE_BINARY_DIR}/test/test_journal.db" COPYONLY) diff --git a/OWNCLOUD.cmake b/OWNCLOUD.cmake index 4022212e62..1a818a4d05 100644 --- a/OWNCLOUD.cmake +++ b/OWNCLOUD.cmake @@ -3,6 +3,7 @@ set( APPLICATION_EXECUTABLE "owncloud" ) set( APPLICATION_DOMAIN "owncloud.com" ) set( APPLICATION_VENDOR "ownCloud" ) set( APPLICATION_UPDATE_URL "https://updates.owncloud.com/client/" CACHE string "URL for updater" ) +set( APPLICATION_ICON_NAME "owncloud" ) set( THEME_CLASS "ownCloudTheme" ) set( APPLICATION_REV_DOMAIN "com.owncloud.desktopclient" ) diff --git a/config.h.in b/config.h.in index 1e8f8ecdc7..0cc0ab9cd0 100644 --- a/config.h.in +++ b/config.h.in @@ -17,6 +17,7 @@ #cmakedefine APPLICATION_SHORTNAME "@APPLICATION_SHORTNAME@" #cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@" #cmakedefine APPLICATION_UPDATE_URL "@APPLICATION_UPDATE_URL@" +#cmakedefine APPLICATION_ICON_NAME "@APPLICATION_ICON_NAME@" #cmakedefine ZLIB_FOUND @ZLIB_FOUND@ diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 5ebf0effca..603abea7ae 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -221,15 +221,13 @@ endif() include( AddAppIconMacro ) set(ownCloud_old ${ownCloud}) -# set an icon_app_name. For historical reasons we can not use the -# application_shortname for ownCloud but must rather set it manually. -if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake ) - set(ICON_APP_NAME ${APPLICATION_SHORTNAME}) -else() - set(ICON_APP_NAME "owncloud") +# For historical reasons we can not use the application_shortname +# for ownCloud but must rather set it manually. +if (NOT DEFINED APPLICATION_ICON_NAME) + set(APPLICATION_ICON_NAME ${APPLICATION_SHORTNAME}) endif() -kde4_add_app_icon( ownCloud "${theme_dir}/colored/${ICON_APP_NAME}-icon*.png") +kde4_add_app_icon( ownCloud "${theme_dir}/colored/${APPLICATION_ICON_NAME}-icon*.png") list(APPEND final_src ${ownCloud}) set(ownCloud ${ownCloud_old}) @@ -243,11 +241,11 @@ endif() if(NOT BUILD_OWNCLOUD_OSX_BUNDLE) if(NOT WIN32) - file( GLOB _icons "${theme_dir}/colored/${ICON_APP_NAME}-icon-*.png" ) + file( GLOB _icons "${theme_dir}/colored/${APPLICATION_ICON_NAME}-icon-*.png" ) foreach( _file ${_icons} ) - string( REPLACE "${theme_dir}/colored/${ICON_APP_NAME}-icon-" "" _res ${_file} ) + string( REPLACE "${theme_dir}/colored/${APPLICATION_ICON_NAME}-icon-" "" _res ${_file} ) string( REPLACE ".png" "" _res ${_res} ) - install( FILES ${_file} RENAME ${ICON_APP_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps ) + install( FILES ${_file} RENAME ${APPLICATION_ICON_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps ) endforeach( _file ) endif(NOT WIN32) diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index af6e933ccb..a380be35d6 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -14,6 +14,7 @@ #include "systray.h" #include "theme.h" +#include "config.h" #ifdef USE_FDO_NOTIFICATIONS #include @@ -30,8 +31,8 @@ namespace OCC { void Systray::showMessage(const QString &title, const QString &message, MessageIcon icon, int millisecondsTimeoutHint) { #ifdef USE_FDO_NOTIFICATIONS - if (QDBusInterface(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE).isValid()) { - QList args = QList() << "owncloud" << quint32(0) << "owncloud" + if(QDBusInterface(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE).isValid()) { + QList args = QList() << APPLICATION_NAME << quint32(0) << APPLICATION_ICON_NAME << title << message << QStringList() << QVariantMap() << qint32(-1); QDBusMessage method = QDBusMessage::createMethodCall(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE, "Notify"); method.setArguments(args); From 8a19f2ac65c4a86d8657857fe68fc82631447686 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 1 Jun 2017 10:37:01 +0200 Subject: [PATCH 12/64] ChangeLog: More things that were done until now --- ChangeLog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 98f393db46..20205f17ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,14 +5,16 @@ version 2.4.0 (2017-0X-XX) * Sharing: Add support for multiple public link shares (#5655) * Sharing: Add option to copy/email direct links (#5627) * Sharing: Show warning that links are public +* Sharing: Many UI improvements * Wizards: Never propose an existing folder for syncing (#5597) +* Wizard: Don't show last page anymore, go to settings directly (#5726) * Settings Dialog: Display the user server avatar * Selective Sync: Open sub folder context menu (#5596) +* Selective Sync: Skip excluded folders when reading db * Exclude list: remove .htaccess * Detect maintenance mode (#4485) * Discovery: Increase the MAX_DEPTH and show deep folders as ignored * Downloads: Remove empty temporary if disk space full (#5746) -* Wizard: Don't show not-so-useful result page (#5726) * When creating explorer favorite use more specific windows functions (#5690) * Added owncloudcmd bandwidth limit parameter (#5707) * AccountSettings: Sync with clean discovery on Ctrl-F6 (#5666) @@ -22,6 +24,8 @@ version 2.4.0 (2017-0X-XX) * Switch 3rdparty/json usage to Qt5's QJson (#5710) * Reduce memory usage * Documentation improvements +* Logging improvements (with Qt logging categories), new --logdebug parameter +* Harmonize source code style with clang-format version 2.3.2 (2017-05-08) * Fix more crashes (thanks to everyone submitting to our crash reporter!) From 3d93527a8eda3902486a678a1ed83b23726b3826 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 28 Mar 2017 10:31:38 +0200 Subject: [PATCH 13/64] Authentication with OAuth2 When the OAuth2 app (https://github.com/owncloud/oauth2) is enabled, We will open a browser and perform the OAuth2 authentication Issue: #4798 and https://github.com/owncloud/platform/issues/17 --- src/gui/CMakeLists.txt | 2 + src/gui/creds/httpcredentialsgui.cpp | 63 ++++++++++- src/gui/creds/httpcredentialsgui.h | 23 +++- src/gui/creds/oauth.cpp | 122 ++++++++++++++++++++++ src/gui/creds/oauth.h | 69 ++++++++++++ src/gui/owncloudsetupwizard.cpp | 6 +- src/gui/wizard/owncloudoauthcredspage.cpp | 103 ++++++++++++++++++ src/gui/wizard/owncloudoauthcredspage.h | 60 +++++++++++ src/gui/wizard/owncloudsetuppage.cpp | 2 + src/gui/wizard/owncloudwizard.cpp | 18 +++- src/gui/wizard/owncloudwizard.h | 4 + src/gui/wizard/owncloudwizardcommon.h | 4 +- src/libsync/creds/httpcredentials.cpp | 86 ++++++++++++++- src/libsync/creds/httpcredentials.h | 47 ++++++++- src/libsync/theme.cpp | 10 ++ src/libsync/theme.h | 7 ++ 16 files changed, 606 insertions(+), 20 deletions(-) create mode 100644 src/gui/creds/oauth.cpp create mode 100644 src/gui/creds/oauth.h create mode 100644 src/gui/wizard/owncloudoauthcredspage.cpp create mode 100644 src/gui/wizard/owncloudoauthcredspage.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 603abea7ae..80b8b940a2 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -93,11 +93,13 @@ set(client_SRCS servernotificationhandler.cpp creds/credentialsfactory.cpp creds/httpcredentialsgui.cpp + creds/oauth.cpp wizard/postfixlineedit.cpp wizard/abstractcredswizardpage.cpp wizard/owncloudadvancedsetuppage.cpp wizard/owncloudconnectionmethoddialog.cpp wizard/owncloudhttpcredspage.cpp + wizard/owncloudoauthcredspage.cpp wizard/owncloudsetuppage.cpp wizard/owncloudwizardcommon.cpp wizard/owncloudwizard.cpp diff --git a/src/gui/creds/httpcredentialsgui.cpp b/src/gui/creds/httpcredentialsgui.cpp index 50d2a2367c..9c629ce654 100644 --- a/src/gui/creds/httpcredentialsgui.cpp +++ b/src/gui/creds/httpcredentialsgui.cpp @@ -15,9 +15,14 @@ #include #include +#include +#include +#include +#include #include "creds/httpcredentialsgui.h" #include "theme.h" #include "account.h" +#include using namespace QKeychain; @@ -25,11 +30,61 @@ namespace OCC { void HttpCredentialsGui::askFromUser() { - // The rest of the code assumes that this will be done asynchronously - QMetaObject::invokeMethod(this, "askFromUserAsync", Qt::QueuedConnection); + _password = QString(); // So our QNAM does not add any auth + + // First, we will send a call to the webdav endpoint to check what kind of auth we need. + auto reply = _account->sendRequest("GET", _account->davUrl()); + QTimer::singleShot(30 * 1000, reply, &QNetworkReply::abort); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply] { + reply->deleteLater(); + if (reply->rawHeader("WWW-Authenticate").contains("Bearer ")) { + // OAuth + _asyncAuth.reset(new OAuth(_account, this)); + connect(_asyncAuth.data(), &OAuth::result, + this, &HttpCredentialsGui::asyncAuthResult); + _asyncAuth->start(); + } else if (reply->error() == QNetworkReply::AuthenticationRequiredError) { + // Show the dialog + // We will re-enter the event loop, so better wait the next iteration + QMetaObject::invokeMethod(this, "showDialog", Qt::QueuedConnection); + } else { + // Network error? + emit asked(); + } + }); } -void HttpCredentialsGui::askFromUserAsync() +void HttpCredentialsGui::asyncAuthResult(OAuth::Result r, const QString &user, + const QString &token, const QString &refreshToken) +{ + switch (r) { + case OAuth::NotSupported: + // We will re-enter the event loop, so better wait the next iteration + QMetaObject::invokeMethod(this, "showDialog", Qt::QueuedConnection); + _asyncAuth.reset(0); + return; + case OAuth::Error: + _asyncAuth.reset(0); + emit asked(); + return; + case OAuth::LoggedIn: + break; + } + + if (_user != user) { + QMessageBox::warning(nullptr, tr("Login Error"), tr("You must sign in as user %1").arg(_user)); + _asyncAuth->openBrowser(); + return; + } + _password = token; + _refreshToken = refreshToken; + _ready = true; + persist(); + _asyncAuth.reset(0); + emit asked(); +} + +void HttpCredentialsGui::showDialog() { QString msg = tr("Please enter %1 password:
" "
" @@ -87,6 +142,4 @@ QString HttpCredentialsGui::requestAppPasswordText(const Account *account) return tr("Click here to request an app password from the web interface.") .arg(account->url().toString() + path); } - - } // namespace OCC diff --git a/src/gui/creds/httpcredentialsgui.h b/src/gui/creds/httpcredentialsgui.h index 235fd523ea..0eaeeee812 100644 --- a/src/gui/creds/httpcredentialsgui.h +++ b/src/gui/creds/httpcredentialsgui.h @@ -15,6 +15,9 @@ #pragma once #include "creds/httpcredentials.h" +#include "creds/oauth.h" +#include +#include namespace OCC { @@ -34,10 +37,26 @@ public: : HttpCredentials(user, password, certificate, key) { } - void askFromUser() Q_DECL_OVERRIDE; - Q_INVOKABLE void askFromUserAsync(); + HttpCredentialsGui(const QString &user, const QString &password, const QString &refreshToken, + const QSslCertificate &certificate, const QSslKey &key) + : HttpCredentials(user, password, certificate, key) + { + _refreshToken = refreshToken; + } + + /** + * This will query the server and either uses OAuth via _asyncAuth->start() + * or call showDialog to ask the password + */ + Q_INVOKABLE void askFromUser() Q_DECL_OVERRIDE; static QString requestAppPasswordText(const Account *account); +private slots: + void asyncAuthResult(OAuth::Result, const QString &user, const QString &accessToken, const QString &refreshToken); + void showDialog(); + +private: + QScopedPointer> _asyncAuth; }; } // namespace OCC diff --git a/src/gui/creds/oauth.cpp b/src/gui/creds/oauth.cpp new file mode 100644 index 0000000000..86b261bb3c --- /dev/null +++ b/src/gui/creds/oauth.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) by Olivier Goffart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include +#include "account.h" +#include "creds/oauth.h" +#include +#include +#include "theme.h" + + +namespace OCC { + +OAuth::~OAuth() +{ +} + +static void httpReplyAndClose(QTcpSocket *socket, const char *code, const char *html) +{ + socket->write("HTTP/1.1 "); + socket->write(code); + socket->write("\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: "); + socket->write(QByteArray::number(qstrlen(html))); + socket->write("\r\n\r\n"); + socket->write(html); + socket->disconnectFromHost(); +} + +void OAuth::start() +{ + // Listen on the socket to get a port which will be used in the redirect_uri + if (!_server.listen(QHostAddress::LocalHost)) { + emit result(NotSupported, QString()); + return; + } + + if (!openBrowser()) + return; + + QObject::connect(&_server, &QTcpServer::newConnection, this, [this] { + while (QTcpSocket *socket = _server.nextPendingConnection()) { + QObject::connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater); + QObject::connect(socket, &QIODevice::readyRead, this, [this, socket] { + QByteArray peek = socket->peek(qMin(socket->bytesAvailable(), 4000LL)); //The code should always be within the first 4K + if (peek.indexOf('\n') < 0) + return; // wait until we find a \n + QRegExp rx("^GET /\\?code=([a-zA-Z0-9]+)[& ]"); // Match a /?code=... URL + if (rx.indexIn(peek) != 0) { + httpReplyAndClose(socket, "404 Not Found", "404 Not Found

404 Not Found

"); + return; + } + + // TODO: add redirect to the page on the server + httpReplyAndClose(socket, "200 OK", "

Login Successfull

You can close this window.

"); + + QString code = rx.cap(1); // The 'code' is the first capture of the regexp + + QUrl requestToken(_account->url().toString() + + QLatin1String("/index.php/apps/oauth2/api/v1/token?grant_type=authorization_code&code=") + + code + + QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort())); + requestToken.setUserName(Theme::instance()->oauthClientId()); + requestToken.setPassword(Theme::instance()->oauthClientSecret()); + QNetworkRequest req; + req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + auto reply = _account->sendRequest("POST", requestToken, req); + QTimer::singleShot(30 * 1000, reply, &QNetworkReply::abort); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply] { + auto jsonData = reply->readAll(); + QJsonParseError jsonParseError; + QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object(); + QString accessToken = json["access_token"].toString(); + QString refreshToken = json["refresh_token"].toString(); + QString user = json["user_id"].toString(); + + if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError + || json.isEmpty() || refreshToken.isEmpty() || accessToken.isEmpty() + || json["token_type"].toString() != QLatin1String("Bearer")) { + qDebug() << "Error when getting the accessToken" << reply->error() << json << jsonParseError.errorString(); + emit result(Error); + return; + } + emit result(LoggedIn, user, accessToken, refreshToken); + }); + }); + } + }); + QTimer::singleShot(5 * 60 * 1000, this, [this] { result(Error); }); +} + + +bool OAuth::openBrowser() +{ + Q_ASSERT(_server.isListening()); + auto url = QUrl(_account->url().toString() + + QLatin1String("/index.php/apps/oauth2/authorize?response_type=code&client_id=") + + Theme::instance()->oauthClientId() + + QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort())); + + + if (!QDesktopServices::openUrl(url)) { + // We cannot open the browser, then we claim we don't support OAuth. + emit result(NotSupported, QString()); + return false; + } + return true; +} + +} // namespace OCC diff --git a/src/gui/creds/oauth.h b/src/gui/creds/oauth.h new file mode 100644 index 0000000000..93e7ac209f --- /dev/null +++ b/src/gui/creds/oauth.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) by Olivier Goffart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once +#include +#include + +namespace OCC { + +/** + * Job that do the authorization grant and fetch the access token + * + * Normal workflow: + * + * --> start() + * | + * +----> openBrowser() open the browser to the login page, redirects to http://localhost:xxx + * | + * +----> _server starts listening on a TCP port waiting for an HTTP request with a 'code' + * | + * v + * request the access_token and the refresh_token via 'apps/oauth2/api/v1/token' + * | + * v + * emit result(...) + * + */ +class OAuth : public QObject +{ + Q_OBJECT +public: + OAuth(Account *account, QObject *parent) + : QObject(parent) + , _account(account) + { + } + ~OAuth(); + + enum Result { NotSupported, + LoggedIn, + Error }; + void start(); + bool openBrowser(); + +signals: + /** + * The state has changed. + * when logged in, token has the value of the token. + */ + void result(OAuth::Result result, const QString &user = QString(), const QString &token = QString(), const QString &refreshToken = QString()); + +private: + Account *_account; + QTcpServer _server; +}; + + +} // namespace OCC diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index 9a7359f3ef..2f1d73b101 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -625,7 +625,11 @@ bool DetermineAuthTypeJob::finished() redirection.clear(); } if ((reply()->error() == QNetworkReply::AuthenticationRequiredError) || redirection.isEmpty()) { - emit authType(WizardCommon::HttpCreds); + if (reply()->rawHeader("WWW-Authenticate").contains("Bearer ")) { + emit authType(WizardCommon::OAuth); + } else { + emit authType(WizardCommon::HttpCreds); + } } else if (redirection.toString().endsWith(account()->davPath())) { // do a new run _redirects++; diff --git a/src/gui/wizard/owncloudoauthcredspage.cpp b/src/gui/wizard/owncloudoauthcredspage.cpp new file mode 100644 index 0000000000..50f498a924 --- /dev/null +++ b/src/gui/wizard/owncloudoauthcredspage.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) by Olivier Goffart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "wizard/owncloudoauthcredspage.h" +#include "theme.h" +#include "account.h" +#include "cookiejar.h" +#include "wizard/owncloudwizardcommon.h" +#include "wizard/owncloudwizard.h" +#include "creds/httpcredentialsgui.h" +#include "creds/credentialsfactory.h" + +namespace OCC { + +OwncloudOAuthCredsPage::OwncloudOAuthCredsPage() + : AbstractCredentialsWizardPage() + , _afterInitialSetup(false) + +{ +} + +void OwncloudOAuthCredsPage::setVisible(bool visible) +{ + if (!_afterInitialSetup) { + QWizardPage::setVisible(visible); + return; + } + + if (isVisible() == visible) { + return; + } + if (visible) { + OwncloudWizard *ocWizard = qobject_cast(wizard()); + Q_ASSERT(ocWizard); + ocWizard->account()->setCredentials(CredentialsFactory::create("http")); + _asyncAuth.reset(new OAuth(ocWizard->account().data(), this)); + connect(_asyncAuth.data(), SIGNAL(result(OAuth::Result, QString, QString, QString)), + this, SLOT(asyncAuthResult(OAuth::Result, QString, QString, QString))); + _asyncAuth->start(); + wizard()->hide(); + } else { + // The next or back button was activated, show the wizard again + wizard()->show(); + } +} + +void OwncloudOAuthCredsPage::asyncAuthResult(OAuth::Result r, const QString &user, + const QString &token, const QString &refreshToken) +{ + switch (r) { + case OAuth::NotSupported: + case OAuth::Error: + qWarning() << "FIXME!!!"; + break; + case OAuth::LoggedIn: { + _token = token; + _user = user; + _refreshToken = refreshToken; + OwncloudWizard *ocWizard = qobject_cast(wizard()); + Q_ASSERT(ocWizard); + emit connectToOCUrl(ocWizard->account()->url().toString()); + break; + } + } +} + +void OwncloudOAuthCredsPage::initializePage() +{ + _afterInitialSetup = true; +} + +int OwncloudOAuthCredsPage::nextId() const +{ + return WizardCommon::Page_AdvancedSetup; +} + +void OwncloudOAuthCredsPage::setConnected() +{ + wizard()->show(); +} + +AbstractCredentials *OwncloudOAuthCredsPage::getCredentials() const +{ + OwncloudWizard *ocWizard = qobject_cast(wizard()); + Q_ASSERT(ocWizard); + return new HttpCredentialsGui(_user, _token, _refreshToken, + ocWizard->_clientSslCertificate, ocWizard->_clientSslKey); +} + +} // namespace OCC diff --git a/src/gui/wizard/owncloudoauthcredspage.h b/src/gui/wizard/owncloudoauthcredspage.h new file mode 100644 index 0000000000..2ef6365ddb --- /dev/null +++ b/src/gui/wizard/owncloudoauthcredspage.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) by Olivier Goffart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "wizard/abstractcredswizardpage.h" +#include "accountfwd.h" +#include "creds/oauth.h" + +namespace OCC { + + +class OwncloudOAuthCredsPage : public AbstractCredentialsWizardPage +{ + Q_OBJECT +public: + OwncloudOAuthCredsPage(); + + AbstractCredentials *getCredentials() const Q_DECL_OVERRIDE; + + void initializePage() Q_DECL_OVERRIDE; + int nextId() const Q_DECL_OVERRIDE; + void setConnected(); + +public Q_SLOTS: + void setVisible(bool visible) Q_DECL_OVERRIDE; + void asyncAuthResult(OAuth::Result, const QString &user, const QString &token, + const QString &reniewToken); + +signals: + void connectToOCUrl(const QString &); + +private: + bool _afterInitialSetup; + +public: + QString _user; + QString _token; + QString _refreshToken; + QScopedPointer _asyncAuth; +}; + +} // namespace OCC diff --git a/src/gui/wizard/owncloudsetuppage.cpp b/src/gui/wizard/owncloudsetuppage.cpp index 39710e8923..271c943a2c 100644 --- a/src/gui/wizard/owncloudsetuppage.cpp +++ b/src/gui/wizard/owncloudsetuppage.cpp @@ -203,6 +203,8 @@ int OwncloudSetupPage::nextId() const { if (_authType == WizardCommon::HttpCreds) { return WizardCommon::Page_HttpCreds; + } else if (_authType == WizardCommon::OAuth) { + return WizardCommon::Page_OAuthCreds; } else { return WizardCommon::Page_ShibbolethCreds; } diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index 84068ddd58..eb80a37c0b 100644 --- a/src/gui/wizard/owncloudwizard.cpp +++ b/src/gui/wizard/owncloudwizard.cpp @@ -20,6 +20,7 @@ #include "wizard/owncloudwizard.h" #include "wizard/owncloudsetuppage.h" #include "wizard/owncloudhttpcredspage.h" +#include "wizard/owncloudoauthcredspage.h" #ifndef NO_SHIBBOLETH #include "wizard/owncloudshibbolethcredspage.h" #endif @@ -42,12 +43,11 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) , _account(0) , _setupPage(new OwncloudSetupPage(this)) , _httpCredsPage(new OwncloudHttpCredsPage(this)) - , + , _browserCredsPage(new OwncloudOAuthCredsPage) #ifndef NO_SHIBBOLETH - _shibbolethCredsPage(new OwncloudShibbolethCredsPage) - , + , _shibbolethCredsPage(new OwncloudShibbolethCredsPage) #endif - _advancedSetupPage(new OwncloudAdvancedSetupPage) + , _advancedSetupPage(new OwncloudAdvancedSetupPage) , _resultPage(new OwncloudWizardResultPage) , _credentialsPage(0) , _setupLog() @@ -55,6 +55,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setPage(WizardCommon::Page_ServerSetup, _setupPage); setPage(WizardCommon::Page_HttpCreds, _httpCredsPage); + setPage(WizardCommon::Page_OAuthCreds, _browserCredsPage); #ifndef NO_SHIBBOLETH setPage(WizardCommon::Page_ShibbolethCreds, _shibbolethCredsPage); #endif @@ -70,6 +71,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))); + connect(_browserCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString))); #ifndef NO_SHIBBOLETH connect(_shibbolethCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString))); #endif @@ -142,6 +144,10 @@ void OwncloudWizard::successfulStep() _httpCredsPage->setConnected(); break; + case WizardCommon::Page_OAuthCreds: + _browserCredsPage->setConnected(); + break; + #ifndef NO_SHIBBOLETH case WizardCommon::Page_ShibbolethCreds: _shibbolethCredsPage->setConnected(); @@ -169,7 +175,9 @@ void OwncloudWizard::setAuthType(WizardCommon::AuthType type) _credentialsPage = _shibbolethCredsPage; } else #endif - { + if (type == WizardCommon::OAuth) { + _credentialsPage = _browserCredsPage; + } else { _credentialsPage = _httpCredsPage; } next(); diff --git a/src/gui/wizard/owncloudwizard.h b/src/gui/wizard/owncloudwizard.h index 4b9097f74e..78f5bb444f 100644 --- a/src/gui/wizard/owncloudwizard.h +++ b/src/gui/wizard/owncloudwizard.h @@ -30,6 +30,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcWizard) class OwncloudSetupPage; class OwncloudHttpCredsPage; +class OwncloudOAuthCredsPage; #ifndef NO_SHIBBOLETH class OwncloudShibbolethCredsPage; #endif @@ -94,6 +95,7 @@ private: AccountPtr _account; OwncloudSetupPage *_setupPage; OwncloudHttpCredsPage *_httpCredsPage; + OwncloudOAuthCredsPage *_browserCredsPage; #ifndef NO_SHIBBOLETH OwncloudShibbolethCredsPage *_shibbolethCredsPage; #endif @@ -102,6 +104,8 @@ private: AbstractCredentialsWizardPage *_credentialsPage; QStringList _setupLog; + + friend class OwncloudSetupWizard; }; } // namespace OCC diff --git a/src/gui/wizard/owncloudwizardcommon.h b/src/gui/wizard/owncloudwizardcommon.h index bf6248c2c6..eaad007046 100644 --- a/src/gui/wizard/owncloudwizardcommon.h +++ b/src/gui/wizard/owncloudwizardcommon.h @@ -30,7 +30,8 @@ namespace WizardCommon { enum AuthType { HttpCreds, - Shibboleth + Shibboleth, + OAuth }; enum SyncMode { @@ -42,6 +43,7 @@ namespace WizardCommon { Page_ServerSetup, Page_HttpCreds, Page_ShibbolethCreds, + Page_OAuthCreds, Page_AdvancedSetup, Page_Result }; diff --git a/src/libsync/creds/httpcredentials.cpp b/src/libsync/creds/httpcredentials.cpp index f5e3cc5820..5601d9ae83 100644 --- a/src/libsync/creds/httpcredentials.cpp +++ b/src/libsync/creds/httpcredentials.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -37,6 +39,7 @@ Q_LOGGING_CATEGORY(lcHttpCredentials, "sync.credentials.http", QtInfoMsg) namespace { const char userC[] = "user"; + const char isOAuthC[] = "oauth"; const char clientCertificatePEMC[] = "_clientCertificatePEM"; const char clientKeyPEMC[] = "_clientKeyPEM"; const char authenticationFailedC[] = "owncloud-authentication-failed"; @@ -54,9 +57,20 @@ public: protected: QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) Q_DECL_OVERRIDE { - QByteArray credHash = QByteArray(_cred->user().toUtf8() + ":" + _cred->password().toUtf8()).toBase64(); QNetworkRequest req(request); - req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash); + if (!_cred->password().isEmpty()) { + if (_cred->isUsingOAuth()) { + req.setRawHeader("Authorization", "Bearer " + _cred->password().toUtf8()); + } else { + QByteArray credHash = QByteArray(_cred->user().toUtf8() + ":" + _cred->password().toUtf8()).toBase64(); + req.setRawHeader("Authorization", "Basic " + credHash); + } + } else if (!request.url().password().isEmpty()) { + // Typically the requests to get or refresh the OAuth access token. The client + // credentials are put in the URL from the code making the request. + QByteArray credHash = request.url().userInfo().toUtf8().toBase64(); + req.setRawHeader("Authorization", "Basic " + credHash); + } if (!_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) { // SSL configuration @@ -149,6 +163,13 @@ void HttpCredentials::fetchFromKeychain() // User must be fetched from config file fetchUser(); + if (!_ready && !_refreshToken.isEmpty()) { + // This happens if the credentials are still loaded from the keychain, bur we are called + // here because the auth is invalid, so this means we simply need to refresh the credentials + refreshAccessToken(); + return; + } + const QString kck = keychainKey(_account->url().toString(), _user); if (_ready) { @@ -236,7 +257,13 @@ bool HttpCredentials::stillValid(QNetworkReply *reply) void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob) { QKeychain::ReadPasswordJob *job = static_cast(incomingJob); - _password = job->textData(); + + bool isOauth = _account->credentialSetting(QLatin1String(isOAuthC)).toBool(); + if (isOauth) { + _refreshToken = job->textData(); + } else { + _password = job->textData(); + } if (_user.isEmpty()) { qCWarning(lcHttpCredentials) << "Strange: User is empty!"; @@ -244,7 +271,9 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob) QKeychain::Error error = job->error(); - if (!_password.isEmpty() && error == NoError) { + if (!_refreshToken.isEmpty() && error == NoError) { + refreshAccessToken(); + } else if (!_password.isEmpty() && error == NoError) { // All cool, the keychain did not come back with error. // Still, the password can be empty which indicates a problem and // the password dialog has to be opened. @@ -262,6 +291,41 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob) } } +void HttpCredentials::refreshAccessToken() +{ + QUrl requestToken(_account->url().toString() + + QLatin1String("/index.php/apps/oauth2/api/v1/token?grant_type=refresh_token&refresh_token=") + + _refreshToken); + requestToken.setUserName(Theme::instance()->oauthClientId()); + requestToken.setPassword(Theme::instance()->oauthClientSecret()); + QNetworkRequest req; + req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + auto reply = _account->sendRequest("POST", requestToken, req); + QTimer::singleShot(30 * 1000, reply, &QNetworkReply::abort); + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply] { + reply->deleteLater(); + auto jsonData = reply->readAll(); + QJsonParseError jsonParseError; + QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object(); + QString accessToken = json["access_token"].toString(); + if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty()) { + // Network error maybe? + qDebug() << "Error while refreshing the token" << reply->errorString() << jsonData << jsonParseError.errorString(); + } else if (accessToken.isEmpty()) { + // The token is no longer valid. + qDebug() << "Expired refresh token. Logging out"; + _refreshToken.clear(); + } else { + _ready = true; + _password = accessToken; + _refreshToken = json["refresh_token"].toString(); + persist(); + } + emit fetched(); + }); +} + + void HttpCredentials::invalidateToken() { if (!_password.isEmpty()) { @@ -279,6 +343,12 @@ void HttpCredentials::invalidateToken() return; } + if (!_refreshToken.isEmpty()) { + // Only invalidate the access_token (_password) but keep the _refreshToken in the keychain + // (when coming from forgetSensitiveData, the _refreshToken is cleared) + return; + } + DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName()); addSettingsToJob(_account, job); job->setInsecureFallback(true); @@ -315,6 +385,9 @@ void HttpCredentials::clearQNAMCache() void HttpCredentials::forgetSensitiveData() { + // need to be done before invalidateToken, so it actually deletes the refresh_token from the keychain + _refreshToken.clear(); + invalidateToken(); _previousPassword.clear(); } @@ -327,6 +400,7 @@ void HttpCredentials::persist() } _account->setCredentialSetting(QLatin1String(userC), _user); + _account->setCredentialSetting(QLatin1String(isOAuthC), isUsingOAuth()); // write cert WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName()); @@ -359,7 +433,7 @@ void HttpCredentials::slotWriteClientKeyPEMJobDone(Job *incomingJob) job->setInsecureFallback(false); connect(job, SIGNAL(finished(QKeychain::Job *)), SLOT(slotWriteJobDone(QKeychain::Job *))); job->setKey(keychainKey(_account->url().toString(), _user)); - job->setTextData(_password); + job->setTextData(isUsingOAuth() ? _refreshToken : _password); job->start(); } @@ -378,6 +452,8 @@ void HttpCredentials::slotWriteJobDone(QKeychain::Job *job) void HttpCredentials::slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) { + if (!_ready) + return; Q_UNUSED(authenticator) // Because of issue #4326, we need to set the login and password manually at every requests // Thus, if we reach this signal, those credentials were invalid and we terminate. diff --git a/src/libsync/creds/httpcredentials.h b/src/libsync/creds/httpcredentials.h index 14118e924b..45b01c5ee5 100644 --- a/src/libsync/creds/httpcredentials.h +++ b/src/libsync/creds/httpcredentials.h @@ -32,6 +32,43 @@ class ReadPasswordJob; namespace OCC { +/* + The authentication system is this way because of Shibboleth. + There used to be two different ways to authenticate: Shibboleth and HTTP Basic Auth. + AbstractCredentials can be inherited from both ShibbolethCrendentials and HttpCredentials. + + HttpCredentials is then split in HttpCredentials and HttpCredentialsGui. + + This class handle both HTTP Basic Auth and OAuth. But anything that needs GUI to ask the user + is in HttpCredentialsGui. + + The authentication mechanism looks like this. + + 1) First, AccountState will attempt to load the certificate from the keychain + + ----> fetchFromKeychain ------------------------> shortcut to refreshAccessToken if the cached + | } information is still valid + v } + slotReadClientCertPEMJobDone } There are first 3 QtKeychain jobs to fetch + | } the TLS client keys, if any, and the password + v } (or refresh token + slotReadClientKeyPEMJobDone } + | } + v + slotReadJobDone + | | + | +-------> emit fetched() if OAuth is not used + | + v + refreshAccessToken() + | + v + emit fetched() + + 2) If the credentials is still not valid when fetched() is emitted, the ui, will call askFromUser() + which is implemented in HttpCredentialsGui + + */ class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials { Q_OBJECT @@ -48,15 +85,21 @@ public: bool stillValid(QNetworkReply *reply) Q_DECL_OVERRIDE; void persist() Q_DECL_OVERRIDE; QString user() const Q_DECL_OVERRIDE; + // the password or token QString password() const; void invalidateToken() Q_DECL_OVERRIDE; void forgetSensitiveData() Q_DECL_OVERRIDE; QString fetchUser(); virtual bool sslIsTrusted() { return false; } + void refreshAccessToken(); + // To fetch the user name as early as possible void setAccount(Account *account) Q_DECL_OVERRIDE; + // Whether we are using OAuth + bool isUsingOAuth() const { return !_refreshToken.isNull(); } + private Q_SLOTS: void slotAuthentication(QNetworkReply *, QAuthenticator *); @@ -71,7 +114,8 @@ private Q_SLOTS: protected: QString _user; - QString _password; + QString _password; // user's password, or access_token for OAuth + QString _refreshToken; // OAuth _refreshToken, set if OAuth is used. QString _previousPassword; QString _fetchErrorString; @@ -80,6 +124,7 @@ protected: QSslCertificate _clientSslCertificate; }; + } // namespace OCC #endif diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index 9dd1c88a95..55c44db817 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -503,5 +503,15 @@ QString Theme::quotaBaseFolder() const return QLatin1String("/"); } +QString Theme::oauthClientId() const +{ + return "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69"; +} + +QString Theme::oauthClientSecret() const +{ + return "e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD"; +} + } // end namespace client diff --git a/src/libsync/theme.h b/src/libsync/theme.h index cc51251df5..bb5c858ae6 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -320,6 +320,13 @@ public: */ virtual QString quotaBaseFolder() const; + /** + * The OAuth client_id, secret pair. + * Note that client that change these value cannot connect to un-branded owncloud servers. + */ + virtual QString oauthClientId() const; + virtual QString oauthClientSecret() const; + protected: #ifndef TOKEN_AUTH_ONLY From e3306abbcbf8b283b3b37284287b6b8c50a30983 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Fri, 2 Jun 2017 02:22:13 +0200 Subject: [PATCH 14/64] [tx-robot] updated from transifex --- translations/client_it.ts | 18 +++++++++--------- translations/client_uk.ts | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/translations/client_it.ts b/translations/client_it.ts index e2b34113d8..762cec02bd 100644 --- a/translations/client_it.ts +++ b/translations/client_it.ts @@ -541,7 +541,7 @@ There was an error while accessing the configuration file at %1. - + Si è verificato un errore durante l'accesso al file di configurazione su %1. @@ -2176,7 +2176,7 @@ Non è consigliabile utilizzarlo. File %1 cannot be uploaded because another file with the same name, differing only in case, exists - + Il file %1 non può essere caricato poiché esiste un altro file con lo stesso nome, ma con differenze tra maiuscole e minuscole @@ -2369,7 +2369,7 @@ Non è consigliabile utilizzarlo. Deselect remote folders you do not wish to synchronize. - + Deseleziona le cartelle remote che non desideri sincronizzare. @@ -2552,7 +2552,7 @@ Non è consigliabile utilizzarlo. Anyone with the link has access to the file/folder - + Chiunque sia in possesso del collegamento ha accesso al file/cartella @@ -3079,12 +3079,12 @@ Non è consigliabile utilizzarlo. File names ending with a period are not supported on this file system. - + I nomi del file che terminano con un punto non sono supportati su questo file system. File names containing the character '%1' are not supported on this file system. - + I nomi del file che contengono il carattere '%1' non sono supportati su questo file system. @@ -3493,7 +3493,7 @@ Non è consigliabile utilizzarlo. Ask for confirmation before synchroni&zing folders larger than - + Chiedi conferma prima di sincroni&zzare cartelle più grandi di @@ -3504,7 +3504,7 @@ Non è consigliabile utilizzarlo. Ask for confirmation before synchronizing e&xternal storages - + Chiedi conferma prima di sincroni&zzare archiviazioni esterne @@ -3800,7 +3800,7 @@ Non è consigliabile utilizzarlo. built with %1 - + creato con %1 diff --git a/translations/client_uk.ts b/translations/client_uk.ts index a215d27341..f817777544 100644 --- a/translations/client_uk.ts +++ b/translations/client_uk.ts @@ -2545,7 +2545,7 @@ It is not advisable to use it. Anyone with the link has access to the file/folder - + Будь хто з цім посиланням має доступ до файлу/теки From b02b99003aea0688ee97b6755b206c207d9c326c Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Sat, 3 Jun 2017 02:22:02 +0200 Subject: [PATCH 15/64] [tx-robot] updated from transifex --- translations/client_pt_BR.ts | 2 +- translations/client_sl.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index 9c6c86815a..140bd9c195 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -2554,7 +2554,7 @@ It is not advisable to use it. Anyone with the link has access to the file/folder - Qualquer pessoa com o link tem acesso ao arquivo/pasta + Qualquer pessoa com o endereço tem acesso ao arquivo/pasta diff --git a/translations/client_sl.ts b/translations/client_sl.ts index cf5c03f5b2..57fced1f7a 100644 --- a/translations/client_sl.ts +++ b/translations/client_sl.ts @@ -2557,7 +2557,7 @@ Uporaba ni priporočljiva. Anyone with the link has access to the file/folder - + Vsak, ki ima povezavo ima dostop do datoteke ali mape From 68ee08440ec48a913ff8ff29a18f880e61087447 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Mon, 5 Jun 2017 02:22:03 +0200 Subject: [PATCH 16/64] [tx-robot] updated from transifex --- translations/client_pt_BR.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index 140bd9c195..9c6c86815a 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -2554,7 +2554,7 @@ It is not advisable to use it. Anyone with the link has access to the file/folder - Qualquer pessoa com o endereço tem acesso ao arquivo/pasta + Qualquer pessoa com o link tem acesso ao arquivo/pasta From cc5fe558ba49c7b1142a0215aad845805fb41ff7 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 6 Jun 2017 10:45:15 +0200 Subject: [PATCH 17/64] Fix maintenance mode detection #5755 The server sends "maintenance": "true" which isn't a json boolean... --- src/libsync/connectionvalidator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libsync/connectionvalidator.cpp b/src/libsync/connectionvalidator.cpp index 5816655be7..0b5897f1ff 100644 --- a/src/libsync/connectionvalidator.cpp +++ b/src/libsync/connectionvalidator.cpp @@ -139,7 +139,9 @@ void ConnectionValidator::slotStatusFound(const QUrl &url, const QJsonObject &in return; } - if (info["maintenance"].toBool()) { + // Check for maintenance mode: Servers send "true", so go through QVariant + // to parse it correctly. + if (info["maintenance"].toVariant().toBool()) { reportResult(MaintenanceMode); return; } From 05c1dcef9b35a18d358ab307922eceff312e3304 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 6 Jun 2017 12:59:57 +0200 Subject: [PATCH 18/64] Add extra logging for SQLITE_CANTOPEN errors #5633 --- src/libsync/ownsql.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsync/ownsql.cpp b/src/libsync/ownsql.cpp index 6db35fda5b..9020fb73a6 100644 --- a/src/libsync/ownsql.cpp +++ b/src/libsync/ownsql.cpp @@ -62,6 +62,10 @@ bool SqlDatabase::openHelper(const QString &filename, int sqliteFlags) if (_errId != SQLITE_OK) { qCWarning(lcSql) << "Error:" << _error << "for" << filename; + if (_errId == SQLITE_CANTOPEN) { + qCWarning(lcSql) << "CANTOPEN extended errcode: " << sqlite3_extended_errcode(_db); + qCWarning(lcSql) << "CANTOPEN system errno: " << sqlite3_system_errno(_db); + } close(); return false; } From e2e56f45af059299d942f237ecf9cefbba0c43be Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 6 Jun 2017 14:45:27 +0200 Subject: [PATCH 19/64] ownsql: fix build on jenkins sqlite3_system_errno was only added in sqlite 3.12 --- src/libsync/ownsql.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsync/ownsql.cpp b/src/libsync/ownsql.cpp index 9020fb73a6..69dae78477 100644 --- a/src/libsync/ownsql.cpp +++ b/src/libsync/ownsql.cpp @@ -64,7 +64,9 @@ bool SqlDatabase::openHelper(const QString &filename, int sqliteFlags) qCWarning(lcSql) << "Error:" << _error << "for" << filename; if (_errId == SQLITE_CANTOPEN) { qCWarning(lcSql) << "CANTOPEN extended errcode: " << sqlite3_extended_errcode(_db); +#if SQLITE_VERSION_NUMBER >= 3012000 qCWarning(lcSql) << "CANTOPEN system errno: " << sqlite3_system_errno(_db); +#endif } close(); return false; From c17a6783856720db84516a2e5deb39d4772372ce Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 29 May 2017 13:00:43 +0200 Subject: [PATCH 20/64] FolderStatusModel: fix assert in Qt when the list of subfolder is empty Fix an assert that happens in beginInsertRows when opening a folder and that folder is empty. This can only be reproduced with a debug build of Qt. --- src/gui/folderstatusmodel.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/folderstatusmodel.cpp b/src/gui/folderstatusmodel.cpp index 037285b530..b0f83e9c8e 100644 --- a/src/gui/folderstatusmodel.cpp +++ b/src/gui/folderstatusmodel.cpp @@ -614,6 +614,8 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list) if (!parentInfo) { return; } + ASSERT(parentInfo->_fetching); // we should only get a result if we were doing a fetch + ASSERT(parentInfo->_subs.isEmpty()); if (parentInfo->hasLabel()) { beginRemoveRows(idx, 0, 0); @@ -712,9 +714,11 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list) newSubs.append(newInfo); } - beginInsertRows(idx, 0, newSubs.size() - 1); - parentInfo->_subs = std::move(newSubs); - endInsertRows(); + if (!newSubs.isEmpty()) { + beginInsertRows(idx, 0, newSubs.size() - 1); + parentInfo->_subs = std::move(newSubs); + endInsertRows(); + } for (auto it = undecidedIndexes.begin(); it != undecidedIndexes.end(); ++it) { suggestExpand(idx.child(*it, 0)); From 63c40b45e4153980599aa412c090f671158eeca8 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 6 Jun 2017 14:19:24 +0200 Subject: [PATCH 21/64] OAuth: Fix the secret to the one from commit 05fd985f9f in the oauth2 repository https://github.com/owncloud/oauth2/commit/05fd985f9fb58d7d2305ce2db6fe24fe6fc08c79 --- src/libsync/theme.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index 55c44db817..3c30a797a0 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -510,7 +510,7 @@ QString Theme::oauthClientId() const QString Theme::oauthClientSecret() const { - return "e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD"; + return "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh"; } From 272898a792fa5709e040c4d27d5208ae42abbc5a Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 7 Jun 2017 02:22:13 +0200 Subject: [PATCH 22/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 073f33525c..5bfe53feb9 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -18,6 +18,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 2f915af6909865cde52daea6638a968d118cc665 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Thu, 8 Jun 2017 02:22:10 +0200 Subject: [PATCH 23/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 5bfe53feb9..5eac31756f 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -21,6 +21,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 7eb8219419fe9251ce62ded3bdae197fd796a66e Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Tue, 6 Jun 2017 12:59:57 +0200 Subject: [PATCH 24/64] Add extra logging for SQLITE_CANTOPEN errors #5633 (cherry picked from commit 05c1dcef9b35a18d358ab307922eceff312e3304) --- src/libsync/ownsql.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsync/ownsql.cpp b/src/libsync/ownsql.cpp index 7008ccf52b..6c6337fd6a 100644 --- a/src/libsync/ownsql.cpp +++ b/src/libsync/ownsql.cpp @@ -57,6 +57,10 @@ bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags ) if( _errId != SQLITE_OK ) { qDebug() << "Error:" << _error << "for" << filename; + if (_errId == SQLITE_CANTOPEN) { + qDebug() << "CANTOPEN extended errcode: " << sqlite3_extended_errcode(_db); + qDebug() << "CANTOPEN system errno: " << sqlite3_system_errno(_db); + } close(); return false; } From 18c39197e5814441c3c36a043d73acb922ffd081 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 6 Jun 2017 14:45:27 +0200 Subject: [PATCH 25/64] ownsql: fix build on jenkins sqlite3_system_errno was only added in sqlite 3.12 (cherry picked from commit e2e56f45af059299d942f237ecf9cefbba0c43be) --- src/libsync/ownsql.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsync/ownsql.cpp b/src/libsync/ownsql.cpp index 6c6337fd6a..3702a9d2fd 100644 --- a/src/libsync/ownsql.cpp +++ b/src/libsync/ownsql.cpp @@ -59,7 +59,9 @@ bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags ) qDebug() << "Error:" << _error << "for" << filename; if (_errId == SQLITE_CANTOPEN) { qDebug() << "CANTOPEN extended errcode: " << sqlite3_extended_errcode(_db); +#if SQLITE_VERSION_NUMBER >= 3012000 qDebug() << "CANTOPEN system errno: " << sqlite3_system_errno(_db); +#endif } close(); return false; From 3314a472c3e108d80069d6b6920d883c36e0eaba Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 6 Jun 2017 16:00:41 +0200 Subject: [PATCH 26/64] SyncEngine: SelectiveSync: Remove local files of undelected folder despite other modified files Issue #5783 When the directry that should be removed by selective sync contains changes, we ignore the whole sub tree instead of only ignoreing new files. We cannot ignore the whole directory, we need to ignore only the directory that do not have files to remove --- src/libsync/syncengine.cpp | 34 ++++++++++++++++++++++++++++++++++ test/testsyncengine.cpp | 24 +++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 12d6c879cd..00a795976f 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -1159,6 +1159,7 @@ void SyncEngine::checkForPermission(SyncFileItemVector &syncItems) bool selectiveListOk; auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &selectiveListOk); std::sort(selectiveSyncBlackList.begin(), selectiveSyncBlackList.end()); + SyncFileItemPtr needle; for (SyncFileItemVector::iterator it = syncItems.begin(); it != syncItems.end(); ++it) { if ((*it)->_direction != SyncFileItem::Up) { @@ -1177,8 +1178,41 @@ void SyncEngine::checkForPermission(SyncFileItemVector &syncItems) (*it)->_errorString = tr("Ignored because of the \"choose what to sync\" blacklist"); if ((*it)->_isDirectory) { + auto it_base = it; for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) { it = it_next; + // We want to ignore almost all instructions for items inside selective-sync excluded folders. + //The exception are DOWN/REMOVE actions that remove local files and folders that are + //guaranteed to be up-to-date with their server copies. + if ((*it)->_direction == SyncFileItem::Down && (*it)->_instruction == CSYNC_INSTRUCTION_REMOVE) { + // We need to keep the "delete" items. So we need to un-ignore parent directories + QString parentDir = (*it)->_file; + do { + parentDir = QFileInfo(parentDir).path(); + if (parentDir.isEmpty() || !parentDir.startsWith((*it_base)->destination())) { + break; + } + // Find the parent directory in the syncItems vector. Since the vector + // is sorted we can use a lower_bound, but we need a fake + // SyncFileItemPtr needle to compare against + if (!needle) + needle = SyncFileItemPtr::create(); + needle->_file = parentDir; + auto parent_it = std::lower_bound(it_base, it, needle); + if (parent_it == syncItems.end() || (*parent_it)->destination() != parentDir) { + break; + } + ASSERT((*parent_it)->_isDirectory); + if ((*parent_it)->_instruction != CSYNC_INSTRUCTION_IGNORE) { + break; // already changed + } + (*parent_it)->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + (*parent_it)->_status = SyncFileItem::NoStatus; + (*parent_it)->_errorString.clear(); + + } while (true); + continue; + } (*it)->_instruction = CSYNC_INSTRUCTION_IGNORE; (*it)->_status = SyncFileItem::FileIgnored; (*it)->_errorString = tr("Ignored because of the \"choose what to sync\" blacklist"); diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index 242d5e438b..4200d5e1b3 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -220,7 +220,18 @@ private slots: FileInfo { QStringLiteral("parentFolder"), { FileInfo{ QStringLiteral("subFolder"), { { QStringLiteral("fileA.txt"), 400 }, - { QStringLiteral("fileB.txt"), 400, 'o' } + { QStringLiteral("fileB.txt"), 400, 'o' }, + FileInfo { QStringLiteral("subsubFolder"), { + { QStringLiteral("fileC.txt"), 400 }, + { QStringLiteral("fileD.txt"), 400, 'o' } + }}, + FileInfo{ QStringLiteral("anotherFolder"), { + FileInfo { QStringLiteral("emptyFolder"), { } }, + FileInfo { QStringLiteral("subsubFolder"), { + { QStringLiteral("fileE.txt"), 400 }, + { QStringLiteral("fileF.txt"), 400, 'o' } + }} + }} }} }} }}}; @@ -233,9 +244,11 @@ private slots: {"parentFolder/subFolder/"}); fakeFolder.syncEngine().journal()->avoidReadFromDbOnNextSync("parentFolder/subFolder/"); - // But touch a local file before the next sync, such that the local folder + // But touch local file before the next sync, such that the local folder // can't be removed fakeFolder.localModifier().setContents("parentFolder/subFolder/fileB.txt", 'n'); + fakeFolder.localModifier().setContents("parentFolder/subFolder/subsubFolder/fileD.txt", 'n'); + fakeFolder.localModifier().setContents("parentFolder/subFolder/anotherFolder/subsubFolder/fileF.txt", 'n'); // Several follow-up syncs don't change the state at all, // in particular the remote state doesn't change and fileB.txt @@ -250,8 +263,13 @@ private slots: // The local state should still have subFolderA auto local = fakeFolder.currentLocalState(); QVERIFY(local.find("parentFolder/subFolder")); - QVERIFY(local.find("parentFolder/subFolder/fileA.txt")); + QVERIFY(!local.find("parentFolder/subFolder/fileA.txt")); QVERIFY(local.find("parentFolder/subFolder/fileB.txt")); + QVERIFY(!local.find("parentFolder/subFolder/subsubFolder/fileC.txt")); + QVERIFY(local.find("parentFolder/subFolder/subsubFolder/fileD.txt")); + QVERIFY(!local.find("parentFolder/subFolder/anotherFolder/subsubFolder/fileE.txt")); + QVERIFY(local.find("parentFolder/subFolder/anotherFolder/subsubFolder/fileF.txt")); + QVERIFY(!local.find("parentFolder/subFolder/anotherFolder/emptyFolder")); } } } From e86b6b2246cdd29c3b5a054db081d6725e7e1413 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Fri, 9 Jun 2017 02:22:10 +0200 Subject: [PATCH 27/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ translations/client_tr.ts | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mirall.desktop.in b/mirall.desktop.in index 5eac31756f..6f1e4098f3 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -24,6 +24,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion diff --git a/translations/client_tr.ts b/translations/client_tr.ts index 43c97aff0a..89257277f8 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -1211,7 +1211,7 @@ Continuing the sync as normal will cause all your files to be overwritten by an Ask for confirmation before synchronizing folders larger than - + senkronizasyon dosyaları @@ -2547,7 +2547,7 @@ Kullanmanız önerilmez. Anyone with the link has access to the file/folder - + Dosya/klasör linkine sahip Herkes erişebilir @@ -2583,7 +2583,7 @@ Kullanmanız önerilmez. There was an error when launching the email client to create a new message. Maybe no default email client is configured? - + Yeni mesaj oluşturmak için eposta istemcisini çalıştırıken bir hata oluştu. Belki varsayılan eposta istemcisi ayarlanmamıştır? @@ -3421,7 +3421,7 @@ Kullanmanız önerilmez. Syncing %1 of %2 - + %2 nin %1 i eşitleniyor From 04b6794318133b167acf3665023319bc95ff7f8b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 7 Jun 2017 16:19:34 +0200 Subject: [PATCH 28/64] OAuth: Error handling in the wizard Issues: #5813 and #5811 --- src/gui/CMakeLists.txt | 1 + src/gui/creds/oauth.h | 1 + src/gui/wizard/owncloudoauthcredspage.cpp | 79 ++++++++++++-------- src/gui/wizard/owncloudoauthcredspage.h | 10 +-- src/gui/wizard/owncloudoauthcredspage.ui | 87 +++++++++++++++++++++++ 5 files changed, 144 insertions(+), 34 deletions(-) create mode 100644 src/gui/wizard/owncloudoauthcredspage.ui diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 80b8b940a2..7dc82bb7cb 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -35,6 +35,7 @@ set(client_UI wizard/owncloudadvancedsetuppage.ui wizard/owncloudconnectionmethoddialog.ui wizard/owncloudhttpcredspage.ui + wizard/owncloudoauthcredspage.ui wizard/owncloudsetupnocredspage.ui wizard/owncloudwizardresultpage.ui ) diff --git a/src/gui/creds/oauth.h b/src/gui/creds/oauth.h index 93e7ac209f..fe7fd1c402 100644 --- a/src/gui/creds/oauth.h +++ b/src/gui/creds/oauth.h @@ -50,6 +50,7 @@ public: enum Result { NotSupported, LoggedIn, Error }; + Q_ENUM(Result); void start(); bool openBrowser(); diff --git a/src/gui/wizard/owncloudoauthcredspage.cpp b/src/gui/wizard/owncloudoauthcredspage.cpp index 50f498a924..a4bf5988e7 100644 --- a/src/gui/wizard/owncloudoauthcredspage.cpp +++ b/src/gui/wizard/owncloudoauthcredspage.cpp @@ -27,43 +27,62 @@ namespace OCC { OwncloudOAuthCredsPage::OwncloudOAuthCredsPage() : AbstractCredentialsWizardPage() - , _afterInitialSetup(false) - { + _ui.setupUi(this); + + Theme *theme = Theme::instance(); + _ui.topLabel->hide(); + _ui.bottomLabel->hide(); + QVariant variant = theme->customMedia(Theme::oCSetupTop); + WizardCommon::setupCustomMedia(variant, _ui.topLabel); + variant = theme->customMedia(Theme::oCSetupBottom); + WizardCommon::setupCustomMedia(variant, _ui.bottomLabel); + + WizardCommon::initErrorLabel(_ui.errorLabel); + + setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(Theme::instance()->appNameGUI()))); + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Login in your browser"))); + + connect(_ui.openLinkButton, &QCommandLinkButton::clicked, [this] { + _ui.errorLabel->hide(); + if (_asyncAuth) + _asyncAuth->openBrowser(); + }); } -void OwncloudOAuthCredsPage::setVisible(bool visible) +void OwncloudOAuthCredsPage::initializePage() { - if (!_afterInitialSetup) { - QWizardPage::setVisible(visible); - return; - } + OwncloudWizard *ocWizard = qobject_cast(wizard()); + Q_ASSERT(ocWizard); + ocWizard->account()->setCredentials(CredentialsFactory::create("http")); + _asyncAuth.reset(new OAuth(ocWizard->account().data(), this)); + connect(_asyncAuth.data(), &OAuth::result, this, &OwncloudOAuthCredsPage::asyncAuthResult, Qt::QueuedConnection); + _asyncAuth->start(); + wizard()->hide(); +} - if (isVisible() == visible) { - return; - } - if (visible) { - OwncloudWizard *ocWizard = qobject_cast(wizard()); - Q_ASSERT(ocWizard); - ocWizard->account()->setCredentials(CredentialsFactory::create("http")); - _asyncAuth.reset(new OAuth(ocWizard->account().data(), this)); - connect(_asyncAuth.data(), SIGNAL(result(OAuth::Result, QString, QString, QString)), - this, SLOT(asyncAuthResult(OAuth::Result, QString, QString, QString))); - _asyncAuth->start(); - wizard()->hide(); - } else { - // The next or back button was activated, show the wizard again - wizard()->show(); - } +void OCC::OwncloudOAuthCredsPage::cleanupPage() +{ + // The next or back button was activated, show the wizard again + wizard()->show(); + _asyncAuth.reset(); } void OwncloudOAuthCredsPage::asyncAuthResult(OAuth::Result r, const QString &user, const QString &token, const QString &refreshToken) { switch (r) { - case OAuth::NotSupported: + case OAuth::NotSupported: { + /* OAuth not supported (can't open browser), fallback to HTTP credentials */ + OwncloudWizard *ocWizard = qobject_cast(wizard()); + ocWizard->back(); + ocWizard->setAuthType(WizardCommon::HttpCreds); + break; + } case OAuth::Error: - qWarning() << "FIXME!!!"; + /* Error while getting the access token. (Timeout, or the server did not accept our client credentials */ + _ui.errorLabel->show(); + wizard()->show(); break; case OAuth::LoggedIn: { _token = token; @@ -77,11 +96,6 @@ void OwncloudOAuthCredsPage::asyncAuthResult(OAuth::Result r, const QString &use } } -void OwncloudOAuthCredsPage::initializePage() -{ - _afterInitialSetup = true; -} - int OwncloudOAuthCredsPage::nextId() const { return WizardCommon::Page_AdvancedSetup; @@ -100,4 +114,9 @@ AbstractCredentials *OwncloudOAuthCredsPage::getCredentials() const ocWizard->_clientSslCertificate, ocWizard->_clientSslKey); } +bool OwncloudOAuthCredsPage::isComplete() const +{ + return false; /* We can never go forward manually */ +} + } // namespace OCC diff --git a/src/gui/wizard/owncloudoauthcredspage.h b/src/gui/wizard/owncloudoauthcredspage.h index 2ef6365ddb..f51a1896a0 100644 --- a/src/gui/wizard/owncloudoauthcredspage.h +++ b/src/gui/wizard/owncloudoauthcredspage.h @@ -24,6 +24,9 @@ #include "accountfwd.h" #include "creds/oauth.h" +#include "ui_owncloudoauthcredspage.h" + + namespace OCC { @@ -36,25 +39,24 @@ public: AbstractCredentials *getCredentials() const Q_DECL_OVERRIDE; void initializePage() Q_DECL_OVERRIDE; + void cleanupPage() override; int nextId() const Q_DECL_OVERRIDE; void setConnected(); + bool isComplete() const override; public Q_SLOTS: - void setVisible(bool visible) Q_DECL_OVERRIDE; void asyncAuthResult(OAuth::Result, const QString &user, const QString &token, const QString &reniewToken); signals: void connectToOCUrl(const QString &); -private: - bool _afterInitialSetup; - public: QString _user; QString _token; QString _refreshToken; QScopedPointer _asyncAuth; + Ui_OwncloudOAuthCredsPage _ui; }; } // namespace OCC diff --git a/src/gui/wizard/owncloudoauthcredspage.ui b/src/gui/wizard/owncloudoauthcredspage.ui new file mode 100644 index 0000000000..7b20b6cc45 --- /dev/null +++ b/src/gui/wizard/owncloudoauthcredspage.ui @@ -0,0 +1,87 @@ + + + OwncloudOAuthCredsPage + + + + 0 + 0 + 424 + 373 + + + + Form + + + + + + TextLabel + + + Qt::RichText + + + Qt::AlignCenter + + + true + + + + + + + Please switch to your browser to proceed. + + + true + + + + + + + An error occured while connecting. Please try again. + + + Qt::PlainText + + + + + + + Re-open Browser + + + + + + + Qt::Vertical + + + + 20 + 127 + + + + + + + + TextLabel + + + Qt::RichText + + + + + + + + From 85408961bae3bc98d9f45e40cad2a52f938b5659 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 7 Jun 2017 16:49:38 +0200 Subject: [PATCH 29/64] Wizard: Don't let the second to last page go back with OAuth2 We don't want to re-open the browser in that case. --- src/gui/owncloudsetupwizard.cpp | 2 +- src/gui/wizard/owncloudwizard.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index 2f1d73b101..f124fa265b 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -346,7 +346,7 @@ void OwncloudSetupWizard::slotAuthError() } _ocWizard->show(); - if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds) { + if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds || _ocWizard->currentId() == WizardCommon::Page_OAuthCreds) { _ocWizard->back(); } _ocWizard->displayError(errorMsg, _ocWizard->currentId() == WizardCommon::Page_ServerSetup && checkDowngradeAdvised(reply)); diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp index eb80a37c0b..9fb20ced65 100644 --- a/src/gui/wizard/owncloudwizard.cpp +++ b/src/gui/wizard/owncloudwizard.cpp @@ -201,6 +201,11 @@ void OwncloudWizard::slotCurrentPageChanged(int id) } setOption(QWizard::HaveCustomButton1, id == WizardCommon::Page_AdvancedSetup); + if (id == WizardCommon::Page_AdvancedSetup && _credentialsPage == _browserCredsPage) { + // For OAuth, disable the back button in the Page_AdvancedSetup because we don't want + // to re-open the browser. + button(QWizard::BackButton)->setEnabled(false); + } } void OwncloudWizard::displayError(const QString &msg, bool retryHTTPonly) From 4b0d956b3d5aafd1c6b4c1ef1942e19434ef7518 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 12 Jun 2017 11:50:36 +0200 Subject: [PATCH 30/64] OAuth: Fix a typo in the success message --- src/gui/creds/oauth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/creds/oauth.cpp b/src/gui/creds/oauth.cpp index 86b261bb3c..2022995c28 100644 --- a/src/gui/creds/oauth.cpp +++ b/src/gui/creds/oauth.cpp @@ -64,7 +64,7 @@ void OAuth::start() } // TODO: add redirect to the page on the server - httpReplyAndClose(socket, "200 OK", "

Login Successfull

You can close this window.

"); + httpReplyAndClose(socket, "200 OK", "

Login Successful

You can close this window.

"); QString code = rx.cap(1); // The 'code' is the first capture of the regexp From 3a002a1ddf3e1d71fa38097c84e95a05a6332ec7 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 12 Jun 2017 18:46:57 +0200 Subject: [PATCH 31/64] Update ChangeLog --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 20205f17ba..0e475fa594 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ ChangeLog ========= version 2.4.0 (2017-0X-XX) +* OAuth2 authentication support * Sharing: Add support for multiple public link shares (#5655) * Sharing: Add option to copy/email direct links (#5627) * Sharing: Show warning that links are public @@ -11,10 +12,12 @@ version 2.4.0 (2017-0X-XX) * Settings Dialog: Display the user server avatar * Selective Sync: Open sub folder context menu (#5596) * Selective Sync: Skip excluded folders when reading db +* Selective Sync: SelectiveSync: Remove local files of unselected folder despite other modified files (#5783) * Exclude list: remove .htaccess * Detect maintenance mode (#4485) * Discovery: Increase the MAX_DEPTH and show deep folders as ignored * Downloads: Remove empty temporary if disk space full (#5746) +* Downloads: Re-trigger folder discovery on 404 * When creating explorer favorite use more specific windows functions (#5690) * Added owncloudcmd bandwidth limit parameter (#5707) * AccountSettings: Sync with clean discovery on Ctrl-F6 (#5666) @@ -26,6 +29,7 @@ version 2.4.0 (2017-0X-XX) * Documentation improvements * Logging improvements (with Qt logging categories), new --logdebug parameter * Harmonize source code style with clang-format +* Crash fixes version 2.3.2 (2017-05-08) * Fix more crashes (thanks to everyone submitting to our crash reporter!) From 6e57b0219edd7dcc99509620277bb53478d958a6 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 13 Jun 2017 09:58:20 +0200 Subject: [PATCH 32/64] Don't link dirrectly against openssl All our crypto code is handled by qt nodaways. No need to carry this dependency. Especially since it causes warnings on system where there are twp openssl version installed: /usr/bin/ld: warning: libcrypto.so.1.0.0, needed by /usr/lib/libQt5Network.so.5.9.0, may conflict with libcrypto.so.1.1 --- CMakeLists.txt | 2 - cmake/modules/FindOpenSSLCross.cmake | 306 --------------------------- doc/building.rst | 11 +- src/gui/CMakeLists.txt | 1 - src/gui/application.cpp | 2 - src/libsync/CMakeLists.txt | 2 - src/libsync/theme.cpp | 6 - 7 files changed, 4 insertions(+), 326 deletions(-) delete mode 100644 cmake/modules/FindOpenSSLCross.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 978b353478..3f02c9e9a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,8 +153,6 @@ 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" ) endif() -find_package(OpenSSL 1.0.0 REQUIRED) - if(APPLE) find_package(Sparkle) endif(APPLE) diff --git a/cmake/modules/FindOpenSSLCross.cmake b/cmake/modules/FindOpenSSLCross.cmake deleted file mode 100644 index 0191714355..0000000000 --- a/cmake/modules/FindOpenSSLCross.cmake +++ /dev/null @@ -1,306 +0,0 @@ -# - Try to find the OpenSSL encryption library -# Once done this will define -# -# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL -# -# Read-Only variables: -# OPENSSL_FOUND - system has the OpenSSL library -# OPENSSL_INCLUDE_DIR - the OpenSSL include directory -# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL -# OPENSSL_VERSION - This is set to $major.$minor.$revision$path (eg. 0.9.8s) - -#============================================================================= -# Copyright 2006-2009 Kitware, Inc. -# Copyright 2006 Alexander Neundorf -# Copyright 2009-2011 Mathieu Malaterre -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -if (UNIX) - find_package(PkgConfig QUIET) - pkg_check_modules(_OPENSSL QUIET openssl) -endif (UNIX) - -# http://www.slproweb.com/products/Win32OpenSSL.html -SET(_OPENSSL_ROOT_HINTS - $ENV{OPENSSL_ROOT_DIR} - ${OPENSSL_ROOT_DIR} - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" - ) -SET(_OPENSSL_ROOT_PATHS - "$ENV{PROGRAMFILES}/OpenSSL" - "$ENV{PROGRAMFILES}/OpenSSL-Win32" - "$ENV{PROGRAMFILES}/OpenSSL-Win64" - "C:/OpenSSL/" - "C:/OpenSSL-Win32/" - "C:/OpenSSL-Win64/" - ) -SET(_OPENSSL_ROOT_HINTS_AND_PATHS - HINTS ${_OPENSSL_ROOT_HINTS} - PATHS ${_OPENSSL_ROOT_PATHS} - ) - -FIND_PATH(OPENSSL_INCLUDE_DIR - NAMES - openssl/ssl.h - HINTS - ${_OPENSSL_INCLUDEDIR} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - include -) - -IF(WIN32 AND NOT CYGWIN) - # MINGW should go here too - IF(MSVC) - # /MD and /MDd are the standard values - if someone wants to use - # others, the libnames have to change here too - # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b - # TODO: handle /MT and static lib - # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: - # * MD for dynamic-release - # * MDd for dynamic-debug - # * MT for static-release - # * MTd for static-debug - - # Implementation details: - # We are using the libraries located in the VC subdir instead of the parent directory eventhough : - # libeay32MD.lib is identical to ../libeay32.lib, and - # ssleay32MD.lib is identical to ../ssleay32.lib - FIND_LIBRARY(LIB_EAY_DEBUG - NAMES - libeay32MDd - libeay32 - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "VC" - "lib/VC" - ) - - FIND_LIBRARY(LIB_EAY_RELEASE - NAMES - libeay32MD - libeay32 - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "VC" - "lib/VC" - ) - - FIND_LIBRARY(SSL_EAY_DEBUG - NAMES - ssleay32MDd - ssleay32 - ssl - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "VC" - "lib/VC" - ) - - FIND_LIBRARY(SSL_EAY_RELEASE - NAMES - ssleay32MD - ssleay32 - ssl - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "VC" - "lib/VC" - ) - - if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) - set( OPENSSL_LIBRARIES - optimized ${SSL_EAY_RELEASE} debug ${SSL_EAY_DEBUG} - optimized ${LIB_EAY_RELEASE} debug ${LIB_EAY_DEBUG} - ) - else() - set( OPENSSL_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} ) - endif() - MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE) - MARK_AS_ADVANCED(LIB_EAY_DEBUG LIB_EAY_RELEASE) - ELSEIF(MINGW) - # same player, for MingW - FIND_LIBRARY(LIB_EAY - NAMES - libeay32 - crypto - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "lib/MinGW" - ) - - FIND_LIBRARY(SSL_EAY - NAMES - ssleay32 - ssl - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib" - "lib/MinGW" - ) - - MARK_AS_ADVANCED(SSL_EAY LIB_EAY) - set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) - ELSE(MSVC) - # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: - FIND_LIBRARY(LIB_EAY - NAMES - libeay32 - HINTS - ${_OPENSSL_LIBDIR} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - lib - ) - - FIND_LIBRARY(SSL_EAY - NAMES - ssleay32 - HINTS - ${_OPENSSL_LIBDIR} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - lib - ) - - MARK_AS_ADVANCED(SSL_EAY LIB_EAY) - set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) - ENDIF(MSVC) -ELSE(WIN32 AND NOT CYGWIN) - - FIND_LIBRARY(OPENSSL_SSL_LIBRARY - NAMES - ssl - ssleay32 - ssleay32MD - HINTS - ${_OPENSSL_LIBDIR} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - lib - ) - - FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARY - NAMES - crypto - HINTS - ${_OPENSSL_LIBDIR} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - lib - ) - - MARK_AS_ADVANCED(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY) - - # compat defines - SET(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY}) - SET(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) - - SET(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) - -ENDIF(WIN32 AND NOT CYGWIN) - -function(from_hex HEX DEC) - string(TOUPPER "${HEX}" HEX) - set(_res 0) - string(LENGTH "${HEX}" _strlen) - - while (_strlen GREATER 0) - math(EXPR _res "${_res} * 16") - string(SUBSTRING "${HEX}" 0 1 NIBBLE) - string(SUBSTRING "${HEX}" 1 -1 HEX) - if (NIBBLE STREQUAL "A") - math(EXPR _res "${_res} + 10") - elseif (NIBBLE STREQUAL "B") - math(EXPR _res "${_res} + 11") - elseif (NIBBLE STREQUAL "C") - math(EXPR _res "${_res} + 12") - elseif (NIBBLE STREQUAL "D") - math(EXPR _res "${_res} + 13") - elseif (NIBBLE STREQUAL "E") - math(EXPR _res "${_res} + 14") - elseif (NIBBLE STREQUAL "F") - math(EXPR _res "${_res} + 15") - else() - math(EXPR _res "${_res} + ${NIBBLE}") - endif() - - string(LENGTH "${HEX}" _strlen) - endwhile() - - set(${DEC} ${_res} PARENT_SCOPE) -endfunction(from_hex) - -if (OPENSSL_INCLUDE_DIR) - if (_OPENSSL_VERSION) - set(OPENSSL_VERSION "${_OPENSSL_VERSION}") - elseif(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h") - file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str - REGEX "^#define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*") - - # The version number is encoded as 0xMNNFFPPS: major minor fix patch status - # The status gives if this is a developer or prerelease and is ignored here. - # Major, minor, and fix directly translate into the version numbers shown in - # the string. The patch field translates to the single character suffix that - # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so - # on. - - string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$" - "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}") - list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) - list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) - from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) - list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) - from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) - list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) - - if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") - from_hex("${OPENSSL_VERSION_PATCH}" _tmp) - # 96 is the ASCII code of 'a' minus 1 - math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") - unset(_tmp) - # Once anyone knows how OpenSSL would call the patch versions beyond 'z' - # this should be updated to handle that, too. This has not happened yet - # so it is simply ignored here for now. - string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) - endif (NOT OPENSSL_VERSION_PATCH STREQUAL "00") - - set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") - endif (_OPENSSL_VERSION) -endif (OPENSSL_INCLUDE_DIR) - -include(FindPackageHandleStandardArgs) - -if (OPENSSL_VERSION) - find_package_handle_standard_args(OpenSSL - REQUIRED_VARS - OPENSSL_LIBRARIES - OPENSSL_INCLUDE_DIR - VERSION_VAR - OPENSSL_VERSION - FAIL_MESSAGE - "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR" - ) -else (OPENSSL_VERSION) - find_package_handle_standard_args(OpenSSL "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR" - OPENSSL_LIBRARIES - OPENSSL_INCLUDE_DIR - ) -endif (OPENSSL_VERSION) - -MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) diff --git a/doc/building.rst b/doc/building.rst index 1e3a927bb5..7cc6da6987 100644 --- a/doc/building.rst +++ b/doc/building.rst @@ -120,7 +120,6 @@ follow `Windows Installer Build (Cross-Compile)`_ instead. * Make sure that you have CMake_ and Git_. * Download the Qt_ MinGW package. You will use the MinGW version bundled with it. - * Download an `OpenSSL Windows Build`_ (the non-"Light" version) 2. Get the QtKeychain_ sources as well as the latest versions of the ownCloud client from Git as follows:: @@ -130,11 +129,10 @@ follow `Windows Installer Build (Cross-Compile)`_ instead. 3. Open the Qt MinGW shortcut console from the Start Menu -4. Make sure that OpenSSL's ``bin`` directory as well as your qtkeychain source - directories are in your PATH. This will allow CMake to find the library and - headers, as well as allow the ownCloud client to find the DLLs at runtime:: +4. Make sure that your qtkeychain source directories are in your PATH. This will + allow CMake to find the library and headers, as well as allow the ownCloud + client to find the DLLs at runtime:: - set PATH=C:\\bin;%PATH% set PATH=C:\;%PATH% 5. Build qtkeychain **directly in the source directory** so that the DLL is built @@ -251,7 +249,7 @@ To build the most up-to-date version of the client: .. note:: qtkeychain must be compiled with the same prefix e.g ``CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ .`` - .. note:: Example:: ``cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -D_OPENSSL_VERSION=1.0.2a -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1`` + .. note:: Example:: ``cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -DNO_SHIBBOLETH=1`` 4. Call ``make``. @@ -279,7 +277,6 @@ The following are known cmake parameters: .. _Git: http://git-scm.com .. _MacPorts: http://www.macports.org .. _Homebrew: http://mxcl.github.com/homebrew/ -.. _OpenSSL Windows Build: http://slproweb.com/products/Win32OpenSSL.html .. _Qt: http://www.qt.io/download .. _Microsoft Authenticode: https://msdn.microsoft.com/en-us/library/ie/ms537361%28v=vs.85%29.aspx .. _QtKeychain: https://github.com/frankosterfeld/qtkeychain diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 7dc82bb7cb..643bb932cd 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -176,7 +176,6 @@ set(3rdparty_INC ) include_directories(${3rdparty_INC}) -include_directories(${OPENSSL_INCLUDE_DIR}) # csync is required. include_directories(${CMAKE_SOURCE_DIR}/csync/src diff --git a/src/gui/application.cpp b/src/gui/application.cpp index cba117ebba..40bbfb1d7e 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -53,8 +53,6 @@ #include #include -#include - class QSocket; namespace OCC { diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index a2bd91322e..65d68823d1 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -9,7 +9,6 @@ include_directories(${CMAKE_SOURCE_DIR}/csync/src ${CMAKE_BINARY_DIR}/csync ${CMAKE_BINARY_DIR}/csync/src ) -include_directories(${OPENSSL_INCLUDE_DIR}) if ( APPLE ) list(APPEND OS_SPECIFIC_LINK_LIBRARIES @@ -108,7 +107,6 @@ list(APPEND libsync_LINK_TARGETS ${QT_LIBRARIES} ocsync ${OS_SPECIFIC_LINK_LIBRARIES} - ${OPENSSL_LIBRARIES} ) if(QTKEYCHAIN_FOUND OR QT5KEYCHAIN_FOUND) diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index 3c30a797a0..1d1391b1fc 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -12,8 +12,6 @@ * for more details. */ -#include - #include "theme.h" #include "version.h" #include "config.h" @@ -308,11 +306,7 @@ QString Theme::gitSHA1() const .arg(__DATE__) .arg(__TIME__) .arg(QString::fromAscii(qVersion())) -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) .arg(QSslSocket::sslLibraryVersionString()); -#else - .arg(QCoreApplication::translate("ownCloudTheme::about()", "built with %1").arg(QString::fromAscii(OPENSSL_VERSION_TEXT))); -#endif #endif return devString; } From 5100a2daf137ac247904c5bd28549bd15dd34658 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 13 Jun 2017 10:24:26 +0200 Subject: [PATCH 33/64] OAuth: cleanup debug messages - Add category to the all messages (they did not have it was merged right after the patch to add category everywhere, but this code did not have it.) - Make sure there is no warnings in the normal flow. (The wizard does a request without authentication to determine the auth type) --- src/gui/creds/oauth.cpp | 5 +++-- src/libsync/abstractnetworkjob.cpp | 10 ++++++---- src/libsync/creds/httpcredentials.cpp | 5 ++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/gui/creds/oauth.cpp b/src/gui/creds/oauth.cpp index 2022995c28..38e279d293 100644 --- a/src/gui/creds/oauth.cpp +++ b/src/gui/creds/oauth.cpp @@ -21,9 +21,10 @@ #include #include "theme.h" - namespace OCC { +Q_LOGGING_CATEGORY(lcOauth, "sync.credentials.oauth", QtInfoMsg) + OAuth::~OAuth() { } @@ -89,7 +90,7 @@ void OAuth::start() if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty() || refreshToken.isEmpty() || accessToken.isEmpty() || json["token_type"].toString() != QLatin1String("Bearer")) { - qDebug() << "Error when getting the accessToken" << reply->error() << json << jsonParseError.errorString(); + qCWarning(lcOauth) << "Error when getting the accessToken" << reply->error() << json << jsonParseError.errorString(); emit result(Error); return; } diff --git a/src/libsync/abstractnetworkjob.cpp b/src/libsync/abstractnetworkjob.cpp index 25fe28ce38..71984a66ab 100644 --- a/src/libsync/abstractnetworkjob.cpp +++ b/src/libsync/abstractnetworkjob.cpp @@ -152,10 +152,12 @@ void AbstractNetworkJob::slotFinished() } if (_reply->error() != QNetworkReply::NoError) { - qCWarning(lcNetworkJob) << _reply->error() << errorString() - << _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) { - qCWarning(lcNetworkJob) << _reply->rawHeader("Proxy-Authenticate"); + if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) { + qCWarning(lcNetworkJob) << _reply->error() << errorString() + << _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) { + qCWarning(lcNetworkJob) << _reply->rawHeader("Proxy-Authenticate"); + } } emit networkError(_reply); } diff --git a/src/libsync/creds/httpcredentials.cpp b/src/libsync/creds/httpcredentials.cpp index 5601d9ae83..ce37ce93ee 100644 --- a/src/libsync/creds/httpcredentials.cpp +++ b/src/libsync/creds/httpcredentials.cpp @@ -181,7 +181,6 @@ void HttpCredentials::fetchFromKeychain() addSettingsToJob(_account, job); job->setInsecureFallback(false); job->setKey(kck); - qCDebug(lcHttpCredentials) << "-------- ----->" << _clientSslCertificate << _clientSslKey; connect(job, SIGNAL(finished(QKeychain::Job *)), SLOT(slotReadClientCertPEMJobDone(QKeychain::Job *))); job->start(); @@ -310,10 +309,10 @@ void HttpCredentials::refreshAccessToken() QString accessToken = json["access_token"].toString(); if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty()) { // Network error maybe? - qDebug() << "Error while refreshing the token" << reply->errorString() << jsonData << jsonParseError.errorString(); + qCWarning(lcHttpCredentials) << "Error while refreshing the token" << reply->errorString() << jsonData << jsonParseError.errorString(); } else if (accessToken.isEmpty()) { // The token is no longer valid. - qDebug() << "Expired refresh token. Logging out"; + qCDebug(lcHttpCredentials) << "Expired refresh token. Logging out"; _refreshToken.clear(); } else { _ready = true; From ff79cc91072249ca4357bee2753df1713747bdb2 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 14 Jun 2017 02:22:19 +0200 Subject: [PATCH 34/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ translations/client_tr.ts | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mirall.desktop.in b/mirall.desktop.in index 6f1e4098f3..c8cadf3396 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -27,6 +27,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion diff --git a/translations/client_tr.ts b/translations/client_tr.ts index 89257277f8..942f49a531 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -248,17 +248,17 @@ There are folders that were not synchronized because they are too big: - + Çok büyük oldukları için eşitlenmeyen klasörler var: There are folders that were not synchronized because they are external storages: - + Harici depolama diskinde oldukları için eşitlenmeyen klasörler var: There are folders that were not synchronized because they are too big or external storages: - + Çok büyük oldukları için ya da harici depolama alanında oldukları için eşitlenmeyen klasörler var: @@ -546,7 +546,7 @@ Quit ownCloud - + ownCloud'dan çık
@@ -3084,7 +3084,7 @@ Kullanmanız önerilmez. The file name is a reserved name on this file system. - + Dosya adı bu dosya sisteminde ayrılmış bir addır. From 85d8ae6b93e80bab2a0fa872725f61d9c8201c13 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 13 Jun 2017 13:49:26 +0200 Subject: [PATCH 35/64] AccountSettings: Triggering log in re-ask about previously rejected certificates #5819 Issue #5819 --- src/gui/accountsettings.cpp | 1 + src/gui/owncloudgui.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 9eb3a53d25..2f866502ad 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -202,6 +202,7 @@ void AccountSettings::slotOpenAccountWizard() void AccountSettings::slotToggleSignInState() { if (_accountState->isSignedOut()) { + _accountState->account()->resetRejectedCertificates(); _accountState->signIn(); } else { _accountState->signOutByUi(); diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 25418c62ab..684689dae7 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -871,6 +871,7 @@ void ownCloudGui::slotDisplayIdle() void ownCloudGui::slotLogin() { if (auto account = qvariant_cast(sender()->property(propertyAccountC))) { + account->account()->resetRejectedCertificates(); account->signIn(); } else { auto list = AccountManager::instance()->accounts(); From 744208f7012612c418c4c17063e00f6ba54533c3 Mon Sep 17 00:00:00 2001 From: Frederik Juul Christiani Date: Tue, 13 Jun 2017 10:28:12 +0200 Subject: [PATCH 36/64] Initialize stop variable. Avoid stopping the worker thread immediately if the stop variable happens to be true. --- shell_integration/windows/OCUtil/RemotePathChecker.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp index cf8b72bbdd..16449ddc01 100644 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ b/shell_integration/windows/OCUtil/RemotePathChecker.cpp @@ -172,7 +172,8 @@ void RemotePathChecker::workerThreadLoop() RemotePathChecker::RemotePathChecker() - : _watchedDirectories(make_shared>()) + : _stop(false) + , _watchedDirectories(make_shared>()) , _connected(false) , _newQueries(CreateEvent(NULL, true, true, NULL)) , _thread([this]{ this->workerThreadLoop(); }) From fae178f70ba3743a41a7981270c28c038acba6e7 Mon Sep 17 00:00:00 2001 From: Frederik Juul Christiani Date: Tue, 13 Jun 2017 11:23:08 +0200 Subject: [PATCH 37/64] shell_integration/windows: Create _newQueries as a non-signaled auto-reset event. Since ResetEvent() is never called, the call to WaitForMultipleObjects() can always return immediately once the event has been signaled. --- shell_integration/windows/OCUtil/RemotePathChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp index 16449ddc01..4a13c1cd56 100644 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ b/shell_integration/windows/OCUtil/RemotePathChecker.cpp @@ -175,7 +175,7 @@ RemotePathChecker::RemotePathChecker() : _stop(false) , _watchedDirectories(make_shared>()) , _connected(false) - , _newQueries(CreateEvent(NULL, true, true, NULL)) + , _newQueries(CreateEvent(NULL, FALSE, FALSE, NULL)) , _thread([this]{ this->workerThreadLoop(); }) { } From 9daef50ce6baeaeff24596cf72fe4585156ee910 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Wed, 14 Jun 2017 14:17:50 +0200 Subject: [PATCH 38/64] shell/Windows: Update binaries to build 45 --- binary | 2 +- shell_integration/windows/OCUtil/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/binary b/binary index 741b49156b..1818b48380 160000 --- a/binary +++ b/binary @@ -1 +1 @@ -Subproject commit 741b49156bb7b55347c20228d6ff9d4aa493cd91 +Subproject commit 1818b48380f4fc50d482b980e5ec0d347f896a70 diff --git a/shell_integration/windows/OCUtil/Version.h b/shell_integration/windows/OCUtil/Version.h index 0b1db7a6b7..4010a60a10 100644 --- a/shell_integration/windows/OCUtil/Version.h +++ b/shell_integration/windows/OCUtil/Version.h @@ -2,7 +2,7 @@ // This is the number that will end up in the version window of the DLLs. // Increment this version before committing a new build if you are today's shell_integration build master. -#define OCEXT_BUILD_NUM 44 +#define OCEXT_BUILD_NUM 45 #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) From cd411e5fb1e7321a5e0336d9ce53ad169750338c Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 14 Jun 2017 12:01:32 +0200 Subject: [PATCH 39/64] SyncEngineTest: Fix date locale related bug The client is very picky about date strings it accepts. If dates are formatted with a non-C locale (such as localized weekday names), it fails to parse it and tests fail in subtle ways. --- test/syncenginetestutils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index 64b0632840..5be71e0f70 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -346,7 +346,7 @@ public: xml.writeEmptyElement(davUri, QStringLiteral("resourcetype")); auto gmtDate = fileInfo.lastModified.toTimeZone(QTimeZone(0)); - auto stringDate = gmtDate.toString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"); + auto stringDate = QLocale::c().toString(gmtDate, "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); From b28e06608c0f6d9e82bc8b1418f2f516e7347692 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 14 Jun 2017 12:03:10 +0200 Subject: [PATCH 40/64] SyncEngineTest: Send 'checksums' in FakePropfind --- test/syncenginetestutils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index 5be71e0f70..fe4676821b 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -282,6 +282,7 @@ public: QDateTime lastModified = QDateTime::currentDateTime().addDays(-7); QString etag = generateEtag(); QByteArray fileId = generateFileId(); + QByteArray checksums; qint64 size = 0; char contentChar = 'W'; @@ -352,6 +353,7 @@ public: xml.writeTextElement(davUri, QStringLiteral("getetag"), fileInfo.etag); xml.writeTextElement(ocUri, QStringLiteral("permissions"), fileInfo.isShared ? QStringLiteral("SRDNVCKW") : QStringLiteral("RDNVCKW")); xml.writeTextElement(ocUri, QStringLiteral("id"), fileInfo.fileId); + xml.writeTextElement(ocUri, QStringLiteral("checksums"), fileInfo.checksums); xml.writeEndElement(); // prop xml.writeTextElement(davUri, QStringLiteral("status"), "HTTP/1.1 200 OK"); xml.writeEndElement(); // propstat From d50d8b86cf135dff833679b073406e4bdd6deae6 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 14 Jun 2017 12:03:40 +0200 Subject: [PATCH 41/64] SyncEngineTest: Add network override This is useful for monitoring what kind of network requests are sent to the fake server. Such as "did this sync cause an upload?" and "was there a propfind for this path?". It can also inject custom replies. --- test/syncenginetestutils.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index fe4676821b..ee15d8e33b 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -706,10 +706,17 @@ public: class FakeQNAM : public QNetworkAccessManager { +public: + using Override = std::function; + +private: FileInfo _remoteRootFileInfo; FileInfo _uploadFileInfo; // maps a path to an HTTP error QHash _errorPaths; + // monitor requests and optionally provide custom replies + Override _override; + public: FakeQNAM(FileInfo initialRoot) : _remoteRootFileInfo{std::move(initialRoot)} { } FileInfo ¤tRemoteState() { return _remoteRootFileInfo; } @@ -717,6 +724,8 @@ public: QHash &errorPaths() { return _errorPaths; } + void setOverride(const Override &override) { _override = override; } + protected: QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData = 0) { @@ -728,8 +737,13 @@ protected: bool isUpload = request.url().path().startsWith(sUploadUrl.path()); FileInfo &info = isUpload ? _uploadFileInfo : _remoteRootFileInfo; + if (_override) { + if (auto reply = _override(op, request)) + return reply; + } + auto verb = request.attribute(QNetworkRequest::CustomVerbAttribute); - if (verb == QLatin1String("PROPFIND")) + if (verb == "PROPFIND") // Ignore outgoingData always returning somethign good enough, works for now. return new FakePropfindReply{info, op, request, this}; else if (verb == QLatin1String("GET") || op == QNetworkAccessManager::GetOperation) @@ -825,6 +839,7 @@ public: void clear() { _qnam->errorPaths().clear(); } }; ErrorList serverErrorPaths() { return {_fakeQnam}; } + void setServerOverride(const FakeQNAM::Override &override) { _fakeQnam->setOverride(override); } QString localPath() const { // SyncEngine wants a trailing slash From 816096311027bac0f391ea97d0b61b4175e9b8f9 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 14 Jun 2017 12:14:46 +0200 Subject: [PATCH 42/64] Compare the hash of files with identical mtime/size #5589 * For conflicts where mtime and size are identical: a) If there's no remote checksum, skip (unchanged) b) If there's a remote checksum that's a useful hash, create a PropagateDownload job and compute the local hash. If the hashes are identical, don't download the file and just update metadata. * Avoid exposing the existence of checksumTypeId beyond the database layer. This makes handling checksums easier in general because they can usually be treated as a single blob. This change was prompted by the difficulty of producing file_stat_t entries uniformly from PROPFINDs and the database. --- csync/src/csync.c | 5 +-- csync/src/csync.h | 11 +++-- csync/src/csync_private.h | 7 ++- csync/src/csync_reconcile.c | 41 +++++++++++++++-- csync/src/csync_statedb.c | 20 +++++---- csync/src/csync_update.c | 35 ++++++++------- csync/src/vio/csync_vio_file_stat.c | 4 ++ src/libsync/checksums.cpp | 48 ++++++++++---------- src/libsync/checksums.h | 14 +++--- src/libsync/discoveryphase.cpp | 30 ++++++++++++- src/libsync/propagatedownload.cpp | 47 ++++++++++++++++++-- src/libsync/propagatedownload.h | 47 +++++++++++++++++++- src/libsync/propagateremotemove.cpp | 3 +- src/libsync/propagateupload.cpp | 20 ++++----- src/libsync/propagateupload.h | 3 +- src/libsync/propagateuploadng.cpp | 5 +-- src/libsync/propagateuploadv1.cpp | 5 +-- src/libsync/propagatorjobs.cpp | 3 +- src/libsync/syncengine.cpp | 10 +++-- src/libsync/syncfileitem.h | 9 +++- src/libsync/syncjournaldb.cpp | 16 +++---- src/libsync/syncjournalfilerecord.cpp | 9 ++-- src/libsync/syncjournalfilerecord.h | 3 +- test/testsyncengine.cpp | 64 +++++++++++++++++++++++++++ test/testsyncjournaldb.cpp | 14 +++--- 25 files changed, 345 insertions(+), 128 deletions(-) diff --git a/csync/src/csync.c b/csync/src/csync.c index abac02efee..9af6f0fcf8 100644 --- a/csync/src/csync.c +++ b/csync/src/csync.c @@ -376,8 +376,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) { trav.error_status = cur->error_status; trav.has_ignored_files = cur->has_ignored_files; - trav.checksum = cur->checksum; - trav.checksumTypeId = cur->checksumTypeId; + trav.checksumHeader = cur->checksumHeader; if( other_node ) { csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data; @@ -670,7 +669,7 @@ void csync_file_stat_free(csync_file_stat_t *st) SAFE_FREE(st->directDownloadCookies); SAFE_FREE(st->etag); SAFE_FREE(st->destpath); - SAFE_FREE(st->checksum); + SAFE_FREE(st->checksumHeader); SAFE_FREE(st); } } diff --git a/csync/src/csync.h b/csync/src/csync.h index c8664a3784..949c9efd23 100644 --- a/csync/src/csync.h +++ b/csync/src/csync.h @@ -223,6 +223,10 @@ struct csync_vio_file_stat_s { enum csync_vio_file_flags_e flags; char *original_name; // only set if locale conversion fails + + // For remote file stats: the highest quality checksum the server provided + // in the "SHA1:324315da2143" form. + char *checksumHeader; }; csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_new(void); @@ -262,8 +266,7 @@ struct csync_tree_walk_file_s { char *directDownloadUrl; char *directDownloadCookies; - const char *checksum; - uint32_t checksumTypeId; + const char *checksumHeader; struct { int64_t size; @@ -304,8 +307,8 @@ typedef int (*csync_vio_stat_hook) (csync_vio_handle_t *dhhandle, void *userdata); /* Compute the checksum of the given \a checksumTypeId for \a path. */ -typedef const char* (*csync_checksum_hook) ( - const char *path, uint32_t checksumTypeId, void *userdata); +typedef const char *(*csync_checksum_hook)( + const char *path, const char *otherChecksumHeader, void *userdata); /** * @brief Allocate a csync context. diff --git a/csync/src/csync_private.h b/csync/src/csync_private.h index a10b09f6f3..11775f345d 100644 --- a/csync/src/csync_private.h +++ b/csync/src/csync_private.h @@ -191,8 +191,11 @@ struct csync_file_stat_s { char *directDownloadCookies; char remotePerm[REMOTE_PERM_BUF_SIZE+1]; - const char *checksum; - uint32_t checksumTypeId; + // In the local tree, this can hold a checksum and its type if it is + // computed during discovery for some reason. + // In the remote tree, this will have the server checksum, if available. + // In both cases, the format is "SHA1:baff". + const char *checksumHeader; CSYNC_STATUS error_status; diff --git a/csync/src/csync_reconcile.c b/csync/src/csync_reconcile.c index 9d716a80c2..59156e800a 100644 --- a/csync/src/csync_reconcile.c +++ b/csync/src/csync_reconcile.c @@ -65,6 +65,19 @@ static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int } } +/* Returns true if we're reasonably certain that hash equality + * for the header means content equality. + * + * Cryptographic safety is not required - this is mainly + * intended to rule out checksums like Adler32 that are not intended for + * hashing and have high likelihood of collision with particular inputs. + */ +static bool _csync_is_collision_safe_hash(const char *checksum_header) +{ + return strncmp(checksum_header, "SHA1:", 5) == 0 + || strncmp(checksum_header, "MD5:", 4) == 0; +} + /** * The main function in the reconcile pass. * @@ -272,11 +285,31 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) { // Folders of the same path are always considered equals is_conflict = false; } else { + // If the size or mtime is different, it's definitely a conflict. is_conflict = ((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. + + // It could be a conflict even if size and mtime match! + // + // In older client versions we always treated these cases as a + // non-conflict. This behavior is preserved in case the server + // doesn't provide a suitable content hash. + // + // When it does have one, however, we do create a job, but the job + // will compare hashes and avoid the download if they are equal. + const char *remoteChecksumHeader = + (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader); + if (remoteChecksumHeader) { + is_conflict |= _csync_is_collision_safe_hash(remoteChecksumHeader); + } + + // SO: If there is no checksum, we can have !is_conflict here + // even though the files have different content! This is an + // intentional tradeoff. Downloading and comparing files would + // be technically correct in this situation but leads to too + // much waste. + // In particular this kind of NEW/NEW situation with identical + // sizes and mtimes pops up when the local database is lost for + // whatever reason. } if (ctx->current == REMOTE_REPLICA) { // If the files are considered equal, only update the DB with the etag from remote diff --git a/csync/src/csync_statedb.c b/csync/src/csync_statedb.c index 9b87985a8d..056ca48dd6 100644 --- a/csync/src/csync_statedb.c +++ b/csync/src/csync_statedb.c @@ -225,7 +225,12 @@ int csync_statedb_close(CSYNC *ctx) { return rc; } -#define METADATA_COLUMNS "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, contentChecksum, contentChecksumTypeId" +#define METADATA_QUERY \ + "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, " \ + "filesize, ignoredChildrenRemote, " \ + "contentchecksumtype.name || ':' || contentChecksum " \ + "FROM metadata " \ + "LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id" // This funciton parses a line from the metadata table into the given csync_file_stat // structure which it is also allocating. @@ -287,9 +292,8 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3 if(column_count > 13) { (*st)->has_ignored_files = sqlite3_column_int(stmt, 13); } - if(column_count > 15 && sqlite3_column_int(stmt, 15)) { - (*st)->checksum = c_strdup( (char*) sqlite3_column_text(stmt, 14)); - (*st)->checksumTypeId = sqlite3_column_int(stmt, 15); + if (column_count > 14 && sqlite3_column_text(stmt, 14)) { + (*st)->checksumHeader = c_strdup((char *)sqlite3_column_text(stmt, 14)); } } @@ -313,7 +317,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, } if( ctx->statedb.by_hash_stmt == NULL ) { - const char *hash_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE phash=?1"; + const char *hash_query = "SELECT " METADATA_QUERY " WHERE phash=?1"; SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL)); ctx->statedb.lastReturnValue = rc; @@ -356,7 +360,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, } if( ctx->statedb.by_fileid_stmt == NULL ) { - const char *query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE fileid=?1"; + const char *query = "SELECT " METADATA_QUERY " WHERE fileid=?1"; SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL)); ctx->statedb.lastReturnValue = rc; @@ -396,7 +400,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, } if( ctx->statedb.by_inode_stmt == NULL ) { - const char *inode_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE inode=?1"; + const char *inode_query = "SELECT " METADATA_QUERY " WHERE inode=?1"; SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL)); ctx->statedb.lastReturnValue = rc; @@ -439,7 +443,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) { * In other words, anything that is between path+'/' and path+'0', * (because '0' follows '/' in ascii) */ - const char *below_path_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC"; + const char *below_path_query = "SELECT " METADATA_QUERY " WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC"; SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL)); ctx->statedb.lastReturnValue = rc; if( rc != SQLITE_OK ) { diff --git a/csync/src/csync_update.c b/csync/src/csync_update.c index 1951529127..d7587765c3 100644 --- a/csync/src/csync_update.c +++ b/csync/src/csync_update.c @@ -287,16 +287,15 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, // Checksum comparison at this stage is only enabled for .eml files, // check #4754 #4755 bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0; - if (isEmlFile && fs->size == tmp->size && tmp->checksumTypeId) { + if (isEmlFile && fs->size == tmp->size && tmp->checksumHeader) { if (ctx->callbacks.checksum_hook) { - st->checksum = ctx->callbacks.checksum_hook( - file, tmp->checksumTypeId, - ctx->callbacks.checksum_userdata); + st->checksumHeader = ctx->callbacks.checksum_hook( + file, tmp->checksumHeader, + ctx->callbacks.checksum_userdata); } bool checksumIdentical = false; - if (st->checksum) { - st->checksumTypeId = tmp->checksumTypeId; - checksumIdentical = strncmp(st->checksum, tmp->checksum, 1000) == 0; + if (st->checksumHeader) { + checksumIdentical = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; } if (checksumIdentical) { CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path); @@ -381,15 +380,14 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, // Verify the checksum where possible - if (isRename && tmp->checksumTypeId && ctx->callbacks.checksum_hook - && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) { - st->checksum = ctx->callbacks.checksum_hook( - file, tmp->checksumTypeId, - ctx->callbacks.checksum_userdata); - if (st->checksum) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksum, tmp->checksum); - st->checksumTypeId = tmp->checksumTypeId; - isRename = strncmp(st->checksum, tmp->checksum, 1000) == 0; + if (isRename && tmp->checksumHeader && ctx->callbacks.checksum_hook + && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) { + st->checksumHeader = ctx->callbacks.checksum_hook( + file, tmp->checksumHeader, + ctx->callbacks.checksum_userdata); + if (st->checksumHeader) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader, tmp->checksumHeader); + isRename = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; } } @@ -506,6 +504,11 @@ out: strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE); } + // For the remote: propagate the discovered checksum + if (fs->checksumHeader && ctx->current == REMOTE_REPLICA) { + st->checksumHeader = c_strdup(fs->checksumHeader); + } + st->phash = h; st->pathlen = len; memcpy(st->path, (len ? path : ""), len + 1); diff --git a/csync/src/vio/csync_vio_file_stat.c b/csync/src/vio/csync_vio_file_stat.c index bc935d3759..8ebb64f337 100644 --- a/csync/src/vio/csync_vio_file_stat.c +++ b/csync/src/vio/csync_vio_file_stat.c @@ -40,6 +40,9 @@ csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat if (file_stat_cpy->directDownloadUrl) { file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl); } + if (file_stat_cpy->checksumHeader) { + file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader); + } file_stat_cpy->name = c_strdup(file_stat_cpy->name); return file_stat_cpy; } @@ -57,6 +60,7 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) { SAFE_FREE(file_stat->directDownloadCookies); SAFE_FREE(file_stat->name); SAFE_FREE(file_stat->original_name); + SAFE_FREE(file_stat->checksumHeader); SAFE_FREE(file_stat); } diff --git a/src/libsync/checksums.cpp b/src/libsync/checksums.cpp index 00818442fb..eaf36379cc 100644 --- a/src/libsync/checksums.cpp +++ b/src/libsync/checksums.cpp @@ -81,6 +81,8 @@ Q_LOGGING_CATEGORY(lcChecksums, "sync.checksums", QtInfoMsg) QByteArray makeChecksumHeader(const QByteArray &checksumType, const QByteArray &checksum) { + if (checksumType.isEmpty() || checksum.isEmpty()) + return QByteArray(); QByteArray header = checksumType; header.append(':'); header.append(checksum); @@ -105,6 +107,16 @@ bool parseChecksumHeader(const QByteArray &header, QByteArray *type, QByteArray return true; } + +QByteArray parseChecksumHeaderType(const QByteArray &header) +{ + const auto idx = header.indexOf(':'); + if (idx < 0) { + return QByteArray(); + } + return header.left(idx); +} + bool uploadChecksumEnabled() { static bool enabled = qgetenv("OWNCLOUD_DISABLE_CHECKSUM_UPLOAD").isEmpty(); @@ -214,39 +226,27 @@ void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumTy emit validated(checksumType, checksum); } -CSyncChecksumHook::CSyncChecksumHook(SyncJournalDb *journal) - : _journal(journal) +CSyncChecksumHook::CSyncChecksumHook() { } -const char *CSyncChecksumHook::hook(const char *path, uint32_t checksumTypeId, void *this_obj) +const char *CSyncChecksumHook::hook(const char *path, const char *otherChecksumHeader, void * /*this_obj*/) { - CSyncChecksumHook *checksumHook = static_cast(this_obj); - QByteArray checksum = checksumHook->compute(QString::fromUtf8(path), checksumTypeId); + QByteArray type = parseChecksumHeaderType(QByteArray(otherChecksumHeader)); + if (type.isEmpty()) + return NULL; + + QByteArray checksum = ComputeChecksum::computeNow(path, type); if (checksum.isNull()) { + qCWarning(lcChecksums) << "Failed to compute checksum" << type << "for" << path; return NULL; } - char *result = (char *)malloc(checksum.size() + 1); - memcpy(result, checksum.constData(), checksum.size()); - result[checksum.size()] = 0; + QByteArray checksumHeader = makeChecksumHeader(type, checksum); + char *result = (char *)malloc(checksumHeader.size() + 1); + memcpy(result, checksumHeader.constData(), checksumHeader.size()); + result[checksumHeader.size()] = 0; return result; } -QByteArray CSyncChecksumHook::compute(const QString &path, int checksumTypeId) -{ - QByteArray checksumType = _journal->getChecksumType(checksumTypeId); - if (checksumType.isEmpty()) { - qCWarning(lcChecksums) << "Checksum type" << checksumTypeId << "not found"; - return QByteArray(); - } - - QByteArray checksum = ComputeChecksum::computeNow(path, checksumType); - if (checksum.isNull()) { - qCWarning(lcChecksums) << "Failed to compute checksum" << checksumType << "for" << path; - return QByteArray(); - } - - return checksum; -} } diff --git a/src/libsync/checksums.h b/src/libsync/checksums.h index 5d88b0bcb6..a7259f7ecc 100644 --- a/src/libsync/checksums.h +++ b/src/libsync/checksums.h @@ -31,6 +31,9 @@ QByteArray makeChecksumHeader(const QByteArray &checksumType, const QByteArray & /// Parses a checksum header bool parseChecksumHeader(const QByteArray &header, QByteArray *type, QByteArray *checksum); +/// Convenience for getting the type from a checksum header, null if none +QByteArray parseChecksumHeaderType(const QByteArray &header); + /// Checks OWNCLOUD_DISABLE_CHECKSUM_UPLOAD bool uploadChecksumEnabled(); @@ -119,20 +122,15 @@ class OWNCLOUDSYNC_EXPORT CSyncChecksumHook : public QObject { Q_OBJECT public: - explicit CSyncChecksumHook(SyncJournalDb *journal); + explicit CSyncChecksumHook(); /** - * Returns the checksum value for \a path for the given \a checksumTypeId. + * Returns the checksum value for \a path that is comparable to \a otherChecksum. * * Called from csync, where a instance of CSyncChecksumHook has * to be set as userdata. * The return value will be owned by csync. */ - static const char *hook(const char *path, uint32_t checksumTypeId, void *this_obj); - - QByteArray compute(const QString &path, int checksumTypeId); - -private: - SyncJournalDb *_journal; + static const char *hook(const char *path, const char *otherChecksumHeader, void *this_obj); }; } diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp index c8f13784be..16b98faeb2 100644 --- a/src/libsync/discoveryphase.cpp +++ b/src/libsync/discoveryphase.cpp @@ -272,7 +272,8 @@ void DiscoverySingleDirectoryJob::start() << "http://owncloud.org/ns:id" << "http://owncloud.org/ns:downloadURL" << "http://owncloud.org/ns:dDC" - << "http://owncloud.org/ns:permissions"; + << "http://owncloud.org/ns:permissions" + << "http://owncloud.org/ns:checksums"; if (_isRootPath) props << "http://owncloud.org/ns:data-fingerprint"; @@ -294,6 +295,28 @@ void DiscoverySingleDirectoryJob::abort() } } +/** + * Returns the highest-quality checksum in a 'checksums' + * property retrieved from the server. + * + * Example: "ADLER32:1231 SHA1:ab124124 MD5:2131affa21" + * -> "SHA1:ab124124" + */ +static QByteArray findBestChecksum(const QByteArray &checksums) +{ + int i = 0; + // The order of the searches here defines the preference ordering. + if (-1 != (i = checksums.indexOf("SHA1:")) + || -1 != (i = checksums.indexOf("MD5:")) + || -1 != (i = checksums.indexOf("Adler32:"))) { + // Now i is the start of the best checksum + // Grab it until the next space or end of string. + auto checksum = checksums.mid(i); + return checksum.mid(0, checksum.indexOf(" ")); + } + return QByteArray(); +} + static csync_vio_file_stat_t *propertyMapToFileStat(const QMap &map) { csync_vio_file_stat_t *file_stat = csync_vio_file_stat_new(); @@ -343,6 +366,11 @@ static csync_vio_file_stat_t *propertyMapToFileStat(const QMap } else { qCWarning(lcDiscovery) << "permissions too large" << v; } + } else if (property == "checksums") { + QByteArray checksum = findBestChecksum(value.toUtf8()); + if (!checksum.isEmpty()) { + file_stat->checksumHeader = strdup(checksum.constData()); + } } } diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index e669369087..8cc87ccac9 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -344,6 +344,41 @@ void PropagateDownloadFile::start() } } + // If we have a conflict where size and mtime are identical, + // compare the remote checksum to the local one. + // Maybe it's not a real conflict and no download is necessary! + if (_item->_instruction == CSYNC_INSTRUCTION_CONFLICT + && _item->_size == _item->log._other_size + && _item->_modtime == _item->log._other_modtime + && !_item->_checksumHeader.isEmpty()) { + qCDebug(lcPropagateDownload) << _item->_file << "may not need download, computing checksum"; + auto computeChecksum = new ComputeChecksum(this); + computeChecksum->setChecksumType(parseChecksumHeaderType(_item->_checksumHeader)); + connect(computeChecksum, SIGNAL(done(QByteArray, QByteArray)), + SLOT(conflictChecksumComputed(QByteArray, QByteArray))); + computeChecksum->start(propagator()->getFilePath(_item->_file)); + return; + } + + startDownload(); +} + +void PropagateDownloadFile::conflictChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum) +{ + if (makeChecksumHeader(checksumType, checksum) == _item->_checksumHeader) { + qCDebug(lcPropagateDownload) << _item->_file << "remote and local checksum match"; + // No download necessary, just update metadata + updateMetadata(/*isConflict=*/false); + return; + } + startDownload(); +} + +void PropagateDownloadFile::startDownload() +{ + if (propagator()->_abortRequested.fetchAndAddRelaxed(0)) + return; + // do a klaas' case clash check. if (propagator()->localFileNameClash(_item->_file)) { done(SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!").arg(QDir::toNativeSeparators(_item->_file))); @@ -672,7 +707,7 @@ namespace { // Anonymous namespace for the recall feature continue; } - qCInfo(lcPropagateDownload) << "Recalling" << localRecalledFile << "Checksum:" << record._contentChecksumType << record._contentChecksum; + qCInfo(lcPropagateDownload) << "Recalling" << localRecalledFile << "Checksum:" << record._checksumHeader; QString targetPath = makeRecallFileName(recalledFile); @@ -717,8 +752,7 @@ void PropagateDownloadFile::transmissionChecksumValidated(const QByteArray &chec void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum) { - _item->_contentChecksum = checksum; - _item->_contentChecksumType = checksumType; + _item->_checksumHeader = makeChecksumHeader(checksumType, checksum); downloadFinished(); } @@ -827,6 +861,13 @@ void PropagateDownloadFile::downloadFinished() // Get up to date information for the journal. _item->_size = FileSystem::getSize(fn); + updateMetadata(isConflict); +} + +void PropagateDownloadFile::updateMetadata(bool isConflict) +{ + QString fn = propagator()->getFilePath(_item->_file); + if (!propagator()->_journal->setFileRecord(SyncJournalFileRecord(*_item, fn))) { done(SyncFileItem::FatalError, tr("Error writing metadata to the database")); return; diff --git a/src/libsync/propagatedownload.h b/src/libsync/propagatedownload.h index 69962131b5..26361541c2 100644 --- a/src/libsync/propagatedownload.h +++ b/src/libsync/propagatedownload.h @@ -106,6 +106,40 @@ private slots: /** * @brief The PropagateDownloadFile class * @ingroup libsync + * + * This is the flow: + +\code{.unparsed} + start() + | + | deleteExistingFolder() if enabled + | + +--> mtime and size identical? + | then compute the local checksum + | done?-> conflictChecksumComputed() + | | + | checksum differs? | + +-> startDownload() <--------------------------+ + | | + +-> run a GETFileJob | checksum identical? + | + done?-> slotGetFinished() | + | | + +-> validate checksum header | + | + done?-> transmissionChecksumValidated() | + | | + +-> compute the content checksum | + | + done?-> contentChecksumComputed() | + | | + +-> downloadFinished() | + | | + +------------------+ | + | | + +-> updateMetadata() <-------------------------+ + +\endcode */ class PropagateDownloadFile : public PropagateItemJob { @@ -136,11 +170,22 @@ public: void setDeleteExistingFolder(bool enabled); private slots: + /// Called when ComputeChecksum on the local file finishes, + /// maybe the local and remote checksums are identical? + void conflictChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum); + /// Called to start downloading the remote file + void startDownload(); + /// Called when the GETFileJob finishes void slotGetFinished(); - void abort() Q_DECL_OVERRIDE; + /// Called when the download's checksum header was validated void transmissionChecksumValidated(const QByteArray &checksumType, const QByteArray &checksum); + /// Called when the download's checksum computation is done void contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum); void downloadFinished(); + /// Called when it's time to update the db metadata + void updateMetadata(bool isConflict); + + void abort() Q_DECL_OVERRIDE; void slotDownloadProgress(qint64, qint64); void slotChecksumFail(const QString &errMsg); diff --git a/src/libsync/propagateremotemove.cpp b/src/libsync/propagateremotemove.cpp index 7f4f96c33c..69979b1a97 100644 --- a/src/libsync/propagateremotemove.cpp +++ b/src/libsync/propagateremotemove.cpp @@ -173,8 +173,7 @@ void PropagateRemoteMove::finalize() SyncJournalFileRecord record(*_item, propagator()->getFilePath(_item->_renameTarget)); record._path = _item->_renameTarget; if (oldRecord.isValid()) { - record._contentChecksum = oldRecord._contentChecksum; - record._contentChecksumType = oldRecord._contentChecksumType; + record._checksumHeader = oldRecord._checksumHeader; if (record._fileSize != oldRecord._fileSize) { qCWarning(lcPropagateRemoteMove) << "File sizes differ on server vs sync journal: " << record._fileSize << oldRecord._fileSize; diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index 93849dff73..f3b0e8336b 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -231,9 +231,10 @@ void PropagateUploadFileCommon::slotComputeContentChecksum() QByteArray checksumType = contentChecksumType(); // Maybe the discovery already computed the checksum? - if (_item->_contentChecksumType == checksumType - && !_item->_contentChecksum.isEmpty()) { - slotComputeTransmissionChecksum(checksumType, _item->_contentChecksum); + QByteArray existingChecksumType, existingChecksum; + parseChecksumHeader(_item->_checksumHeader, &existingChecksumType, &existingChecksum); + if (existingChecksumType == checksumType) { + slotComputeTransmissionChecksum(checksumType, existingChecksum); return; } @@ -250,8 +251,7 @@ void PropagateUploadFileCommon::slotComputeContentChecksum() void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray &contentChecksumType, const QByteArray &contentChecksum) { - _item->_contentChecksum = contentChecksum; - _item->_contentChecksumType = contentChecksumType; + _item->_checksumHeader = makeChecksumHeader(contentChecksumType, contentChecksum); #ifdef WITH_TESTING _stopWatch.addLapTime(QLatin1String("ContentChecksum")); @@ -288,13 +288,11 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray &transmissionCh // When we start chunks, we will add it again, once for every chunks. propagator()->_activeJobList.removeOne(this); - _transmissionChecksum = transmissionChecksum; - _transmissionChecksumType = transmissionChecksumType; + _transmissionChecksumHeader = makeChecksumHeader(transmissionChecksumType, transmissionChecksum); - if (_item->_contentChecksum.isEmpty() && _item->_contentChecksumType.isEmpty()) { - // If the _contentChecksum was not set, reuse the transmission checksum as the content checksum. - _item->_contentChecksum = transmissionChecksum; - _item->_contentChecksumType = transmissionChecksumType; + // If no checksum header was not set, reuse the transmission checksum as the content checksum. + if (_item->_checksumHeader.isEmpty()) { + _item->_checksumHeader = _transmissionChecksumHeader; } const QString fullFilePath = propagator()->getFilePath(_item->_file); diff --git a/src/libsync/propagateupload.h b/src/libsync/propagateupload.h index e9130d9340..5e16b5ff98 100644 --- a/src/libsync/propagateupload.h +++ b/src/libsync/propagateupload.h @@ -226,8 +226,7 @@ protected: Utility::StopWatch _stopWatch; #endif - QByteArray _transmissionChecksum; - QByteArray _transmissionChecksumType; + QByteArray _transmissionChecksumHeader; public: PropagateUploadFileCommon(OwncloudPropagator *propagator, const SyncFileItemPtr &item) diff --git a/src/libsync/propagateuploadng.cpp b/src/libsync/propagateuploadng.cpp index d6c213389d..45768102da 100644 --- a/src/libsync/propagateuploadng.cpp +++ b/src/libsync/propagateuploadng.cpp @@ -283,9 +283,8 @@ void PropagateUploadFileNG::startNextChunk() if (!ifMatch.isEmpty()) { headers["If"] = "<" + destination.toUtf8() + "> ([" + ifMatch + "])"; } - if (!_transmissionChecksumType.isEmpty()) { - headers[checkSumHeaderC] = makeChecksumHeader( - _transmissionChecksumType, _transmissionChecksum); + if (!_transmissionChecksumHeader.isEmpty()) { + headers[checkSumHeaderC] = _transmissionChecksumHeader; } headers["OC-Total-Length"] = QByteArray::number(fileSize); diff --git a/src/libsync/propagateuploadv1.cpp b/src/libsync/propagateuploadv1.cpp index f8a88020dd..b48b433ab7 100644 --- a/src/libsync/propagateuploadv1.cpp +++ b/src/libsync/propagateuploadv1.cpp @@ -103,9 +103,8 @@ void PropagateUploadFileV1::startNextChunk() } qCDebug(lcPropagateUpload) << _chunkCount << isFinalChunk << chunkStart << currentChunkSize; - if (isFinalChunk && !_transmissionChecksumType.isEmpty()) { - headers[checkSumHeaderC] = makeChecksumHeader( - _transmissionChecksumType, _transmissionChecksum); + if (isFinalChunk && !_transmissionChecksumHeader.isEmpty()) { + headers[checkSumHeaderC] = _transmissionChecksumHeader; } const QString fileName = propagator()->getFilePath(_item->_file); diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp index bda94fa11f..5cf17b26ac 100644 --- a/src/libsync/propagatorjobs.cpp +++ b/src/libsync/propagatorjobs.cpp @@ -241,8 +241,7 @@ void PropagateLocalRename::start() SyncJournalFileRecord record(*_item, targetFile); record._path = _item->_renameTarget; if (oldRecord.isValid()) { - record._contentChecksum = oldRecord._contentChecksum; - record._contentChecksumType = oldRecord._contentChecksumType; + record._checksumHeader = oldRecord._checksumHeader; } if (!_item->_isDirectory) { // Directories are saved at the end diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 00a795976f..d65646ff8b 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -73,7 +73,6 @@ SyncEngine::SyncEngine(AccountPtr account, const QString &localPath, , _backInTimeFiles(0) , _uploadLimit(0) , _downloadLimit(0) - , _checksum_hook(journal) , _anotherSyncNeeded(NoFollowUpSync) { qRegisterMetaType("SyncFileItem"); @@ -426,9 +425,12 @@ int SyncEngine::treewalkFile(TREE_WALK_FILE *file, bool remote) } // Sometimes the discovery computes checksums for local files - if (!remote && file->checksum && file->checksumTypeId) { - item->_contentChecksum = QByteArray(file->checksum); - item->_contentChecksumType = _journal->getChecksumType(file->checksumTypeId); + if (!remote && file->checksumHeader) { + item->_checksumHeader = QByteArray(file->checksumHeader); + } + // For conflicts, store the remote checksum there + if (remote && item->_instruction == CSYNC_INSTRUCTION_CONFLICT && file->checksumHeader) { + item->_checksumHeader = QByteArray(file->checksumHeader); } // record the seen files to be able to clean the journal later diff --git a/src/libsync/syncfileitem.h b/src/libsync/syncfileitem.h index 6273dd5c96..3eefac5cee 100644 --- a/src/libsync/syncfileitem.h +++ b/src/libsync/syncfileitem.h @@ -190,8 +190,13 @@ public: quint64 _inode; QByteArray _fileId; QByteArray _remotePerm; - QByteArray _contentChecksum; - QByteArray _contentChecksumType; + + // When is this set, and is it the local or the remote checksum? + // - if mtime or size changed locally for *.eml files (local checksum) + // - for potential renames of local files (local checksum) + // - for conflicts (remote checksum) (what about eval_rename/new reconcile?) + QByteArray _checksumHeader; + QString _directDownloadUrl; QString _directDownloadCookies; diff --git a/src/libsync/syncjournaldb.cpp b/src/libsync/syncjournaldb.cpp index c6b67fd067..3406c7e357 100644 --- a/src/libsync/syncjournaldb.cpp +++ b/src/libsync/syncjournaldb.cpp @@ -28,6 +28,7 @@ #include "version.h" #include "filesystem.h" #include "asserts.h" +#include "checksums.h" #include "../../csync/src/std/c_jhash.h" @@ -448,7 +449,7 @@ bool SyncJournalDb::checkConnect() _getFileRecordQuery.reset(new SqlQuery(_db)); if (_getFileRecordQuery->prepare( "SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize," - " ignoredChildrenRemote, contentChecksum, contentchecksumtype.name" + " ignoredChildrenRemote, contentchecksumtype.name || ':' || contentChecksum" " FROM metadata" " LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id" " WHERE phash=?1")) { @@ -832,7 +833,7 @@ bool SyncJournalDb::setFileRecord(const SyncJournalFileRecord &_record) qCInfo(lcDb) << "Updating file record for path:" << record._path << "inode:" << record._inode << "modtime:" << record._modtime << "type:" << record._type << "etag:" << record._etag << "fileId:" << record._fileId << "remotePerm:" << record._remotePerm - << "fileSize:" << record._fileSize << "checksum:" << record._contentChecksum << record._contentChecksumType; + << "fileSize:" << record._fileSize << "checksum:" << record._checksumHeader; qlonglong phash = getPHash(record._path); if (checkConnect()) { @@ -848,7 +849,9 @@ bool SyncJournalDb::setFileRecord(const SyncJournalFileRecord &_record) QString remotePerm(record._remotePerm); if (remotePerm.isEmpty()) remotePerm = QString(); // have NULL in DB (vs empty) - int contentChecksumTypeId = mapChecksumType(record._contentChecksumType); + QByteArray checksumType, checksum; + parseChecksumHeader(record._checksumHeader, &checksumType, &checksum); + int contentChecksumTypeId = mapChecksumType(checksumType); _setFileRecordQuery->reset_and_clear_bindings(); _setFileRecordQuery->bindValue(1, QString::number(phash)); _setFileRecordQuery->bindValue(2, plen); @@ -864,7 +867,7 @@ bool SyncJournalDb::setFileRecord(const SyncJournalFileRecord &_record) _setFileRecordQuery->bindValue(12, remotePerm); _setFileRecordQuery->bindValue(13, record._fileSize); _setFileRecordQuery->bindValue(14, record._serverHasIgnoredFiles ? 1 : 0); - _setFileRecordQuery->bindValue(15, record._contentChecksum); + _setFileRecordQuery->bindValue(15, checksum); _setFileRecordQuery->bindValue(16, contentChecksumTypeId); if (!_setFileRecordQuery->exec()) { @@ -943,10 +946,7 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord(const QString &filename) rec._remotePerm = _getFileRecordQuery->baValue(9); rec._fileSize = _getFileRecordQuery->int64Value(10); rec._serverHasIgnoredFiles = (_getFileRecordQuery->intValue(11) > 0); - rec._contentChecksum = _getFileRecordQuery->baValue(12); - if (!_getFileRecordQuery->nullValue(13)) { - rec._contentChecksumType = _getFileRecordQuery->baValue(13); - } + rec._checksumHeader = _getFileRecordQuery->baValue(12); _getFileRecordQuery->reset_and_clear_bindings(); } else { int errId = _getFileRecordQuery->errorId(); diff --git a/src/libsync/syncjournalfilerecord.cpp b/src/libsync/syncjournalfilerecord.cpp index 6937789145..b2c65931d4 100644 --- a/src/libsync/syncjournalfilerecord.cpp +++ b/src/libsync/syncjournalfilerecord.cpp @@ -47,8 +47,7 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt , _fileSize(item._size) , _remotePerm(item._remotePerm) , _serverHasIgnoredFiles(item._serverHasIgnoredFiles) - , _contentChecksum(item._contentChecksum) - , _contentChecksumType(item._contentChecksumType) + , _checksumHeader(item._checksumHeader) { // use the "old" inode coming with the item for the case where the // filesystem stat fails. That can happen if the the file was removed @@ -106,8 +105,7 @@ SyncFileItem SyncJournalFileRecord::toSyncFileItem() item._size = _fileSize; item._remotePerm = _remotePerm; item._serverHasIgnoredFiles = _serverHasIgnoredFiles; - item._contentChecksum = _contentChecksum; - item._contentChecksumType = _contentChecksumType; + item._checksumHeader = _checksumHeader; return item; } @@ -130,7 +128,6 @@ bool operator==(const SyncJournalFileRecord &lhs, && lhs._fileSize == rhs._fileSize && lhs._remotePerm == rhs._remotePerm && lhs._serverHasIgnoredFiles == rhs._serverHasIgnoredFiles - && lhs._contentChecksum == rhs._contentChecksum - && lhs._contentChecksumType == rhs._contentChecksumType; + && lhs._checksumHeader == rhs._checksumHeader; } } diff --git a/src/libsync/syncjournalfilerecord.h b/src/libsync/syncjournalfilerecord.h index f96e85b3ba..c7579683b9 100644 --- a/src/libsync/syncjournalfilerecord.h +++ b/src/libsync/syncjournalfilerecord.h @@ -57,8 +57,7 @@ public: qint64 _fileSize; QByteArray _remotePerm; bool _serverHasIgnoredFiles; - QByteArray _contentChecksum; - QByteArray _contentChecksumType; + QByteArray _checksumHeader; }; bool OWNCLOUDSYNC_EXPORT diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index 4200d5e1b3..1f48931da1 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -321,6 +321,70 @@ private slots: } } + void testFakeConflict() + { + FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() }; + + int nGET = 0; + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &) { + if (op == QNetworkAccessManager::GetOperation) + ++nGET; + return nullptr; + }); + + // For directly editing the remote checksum + FileInfo &remoteInfo = dynamic_cast(fakeFolder.remoteModifier()); + + // Base mtime with no ms content (filesystem is seconds only) + auto mtime = QDateTime::currentDateTime().addDays(-4); + mtime.setMSecsSinceEpoch(mtime.toMSecsSinceEpoch() / 1000 * 1000); + + // Conflict: Same content, mtime, but no server checksum + // -> ignored in reconcile + fakeFolder.localModifier().setContents("A/a1", 'C'); + fakeFolder.localModifier().setModTime("A/a1", mtime); + fakeFolder.remoteModifier().setContents("A/a1", 'C'); + fakeFolder.remoteModifier().setModTime("A/a1", mtime); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); + + // Conflict: Same content, mtime, but weak server checksum + // -> ignored in reconcile + mtime = mtime.addDays(1); + fakeFolder.localModifier().setContents("A/a1", 'D'); + fakeFolder.localModifier().setModTime("A/a1", mtime); + fakeFolder.remoteModifier().setContents("A/a1", 'D'); + fakeFolder.remoteModifier().setModTime("A/a1", mtime); + remoteInfo.find("A/a1")->checksums = "Adler32:bad"; + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); + + // Conflict: Same content, mtime, but server checksum differs + // -> downloaded + mtime = mtime.addDays(1); + fakeFolder.localModifier().setContents("A/a1", 'W'); + fakeFolder.localModifier().setModTime("A/a1", mtime); + fakeFolder.remoteModifier().setContents("A/a1", 'W'); + fakeFolder.remoteModifier().setModTime("A/a1", mtime); + remoteInfo.find("A/a1")->checksums = "SHA1:bad"; + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 1); + + // Conflict: Same content, mtime, matching checksums + // -> PropagateDownload, but it skips the download + mtime = mtime.addDays(1); + fakeFolder.localModifier().setContents("A/a1", 'C'); + fakeFolder.localModifier().setModTime("A/a1", mtime); + fakeFolder.remoteModifier().setContents("A/a1", 'C'); + fakeFolder.remoteModifier().setModTime("A/a1", mtime); + remoteInfo.find("A/a1")->checksums = "SHA1:56900fb1d337cf7237ff766276b9c1e8ce507427"; + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 1); + + // Extra sync reads from db, no difference + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 1); + } }; QTEST_GUILESS_MAIN(TestSyncEngine) diff --git a/test/testsyncjournaldb.cpp b/test/testsyncjournaldb.cpp index fa6021acc4..ec673077dc 100644 --- a/test/testsyncjournaldb.cpp +++ b/test/testsyncjournaldb.cpp @@ -53,17 +53,15 @@ private slots: record._fileId = "abcd"; record._remotePerm = "744"; record._fileSize = 213089055; - record._contentChecksum = "mychecksum"; - record._contentChecksumType = "MD5"; + record._checksumHeader = "MD5:mychecksum"; QVERIFY(_db.setFileRecord(record)); SyncJournalFileRecord storedRecord = _db.getFileRecord("foo"); QVERIFY(storedRecord == record); // Update checksum - record._contentChecksum = "newchecksum"; - record._contentChecksumType = "Adler32"; - _db.updateFileRecordChecksum("foo", record._contentChecksum, record._contentChecksumType); + record._checksumHeader = "Adler32:newchecksum"; + _db.updateFileRecordChecksum("foo", "newchecksum", "Adler32"); storedRecord = _db.getFileRecord("foo"); QVERIFY(storedRecord == record); @@ -91,16 +89,14 @@ private slots: SyncJournalFileRecord record; record._path = "foo-checksum"; record._remotePerm = "744"; - record._contentChecksum = "mychecksum"; - record._contentChecksumType = "MD5"; + record._checksumHeader = "MD5:mychecksum"; record._modtime = QDateTime::currentDateTimeUtc(); QVERIFY(_db.setFileRecord(record)); SyncJournalFileRecord storedRecord = _db.getFileRecord("foo-checksum"); QVERIFY(storedRecord._path == record._path); QVERIFY(storedRecord._remotePerm == record._remotePerm); - QVERIFY(storedRecord._contentChecksum == record._contentChecksum); - QVERIFY(storedRecord._contentChecksumType == record._contentChecksumType); + QVERIFY(storedRecord._checksumHeader == record._checksumHeader); // qDebug()<< "OOOOO " << storedRecord._modtime.toTime_t() << record._modtime.toTime_t(); From 5d24a2dc0f063d7de28162e9145ce239e10ac640 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Thu, 15 Jun 2017 20:10:30 +0200 Subject: [PATCH 43/64] Remove debug messages by default from sync.engine Other categories were already set properly. --- src/libsync/syncengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index d65646ff8b..faf003fbf6 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -52,7 +52,7 @@ namespace OCC { -Q_LOGGING_CATEGORY(lcEngine, "sync.engine") +Q_LOGGING_CATEGORY(lcEngine, "sync.engine", QtInfoMsg) bool SyncEngine::s_anySyncRunning = false; From 480388133e41128759d61a3f0fbeea40b1fef87d Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Sat, 17 Jun 2017 02:22:17 +0200 Subject: [PATCH 44/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index c8cadf3396..75663e9edf 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -30,6 +30,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 9c82c36c718b42febba884d00aa90b5ae7f087d2 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Sun, 18 Jun 2017 02:22:08 +0200 Subject: [PATCH 45/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 75663e9edf..8fec651957 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -33,6 +33,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From f348a7d4f45698d89e27b3341a2ac3b069614dd7 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Mon, 19 Jun 2017 02:22:08 +0200 Subject: [PATCH 46/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 8fec651957..92843b0a1b 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -36,6 +36,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From e7d4d12e165ea8c5de59acc10d4f2f9403ae4dc2 Mon Sep 17 00:00:00 2001 From: Frederik Juul Christiani Date: Tue, 13 Jun 2017 10:28:12 +0200 Subject: [PATCH 47/64] Initialize stop variable. Avoid stopping the worker thread immediately if the stop variable happens to be true. --- shell_integration/windows/OCUtil/RemotePathChecker.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp index cf8b72bbdd..16449ddc01 100644 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ b/shell_integration/windows/OCUtil/RemotePathChecker.cpp @@ -172,7 +172,8 @@ void RemotePathChecker::workerThreadLoop() RemotePathChecker::RemotePathChecker() - : _watchedDirectories(make_shared>()) + : _stop(false) + , _watchedDirectories(make_shared>()) , _connected(false) , _newQueries(CreateEvent(NULL, true, true, NULL)) , _thread([this]{ this->workerThreadLoop(); }) From bc2e1a53cbc7dd10c83bb7d69736cb9e750d6571 Mon Sep 17 00:00:00 2001 From: Frederik Juul Christiani Date: Tue, 13 Jun 2017 11:23:08 +0200 Subject: [PATCH 48/64] shell_integration/windows: Create _newQueries as a non-signaled auto-reset event. Since ResetEvent() is never called, the call to WaitForMultipleObjects() can always return immediately once the event has been signaled. --- shell_integration/windows/OCUtil/RemotePathChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp index 16449ddc01..4a13c1cd56 100644 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ b/shell_integration/windows/OCUtil/RemotePathChecker.cpp @@ -175,7 +175,7 @@ RemotePathChecker::RemotePathChecker() : _stop(false) , _watchedDirectories(make_shared>()) , _connected(false) - , _newQueries(CreateEvent(NULL, true, true, NULL)) + , _newQueries(CreateEvent(NULL, FALSE, FALSE, NULL)) , _thread([this]{ this->workerThreadLoop(); }) { } From b20f87eef3fb34885b791d25e3896fa71f958981 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Wed, 14 Jun 2017 14:17:50 +0200 Subject: [PATCH 49/64] shell/Windows: Update binaries to build 45 --- binary | 2 +- shell_integration/windows/OCUtil/Version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/binary b/binary index 741b49156b..1818b48380 160000 --- a/binary +++ b/binary @@ -1 +1 @@ -Subproject commit 741b49156bb7b55347c20228d6ff9d4aa493cd91 +Subproject commit 1818b48380f4fc50d482b980e5ec0d347f896a70 diff --git a/shell_integration/windows/OCUtil/Version.h b/shell_integration/windows/OCUtil/Version.h index 0b1db7a6b7..4010a60a10 100644 --- a/shell_integration/windows/OCUtil/Version.h +++ b/shell_integration/windows/OCUtil/Version.h @@ -2,7 +2,7 @@ // This is the number that will end up in the version window of the DLLs. // Increment this version before committing a new build if you are today's shell_integration build master. -#define OCEXT_BUILD_NUM 44 +#define OCEXT_BUILD_NUM 45 #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) From b50706a7aae96a200bcccb241af8ef72a9731b18 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Tue, 20 Jun 2017 02:22:12 +0200 Subject: [PATCH 50/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 92843b0a1b..65309df6d5 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -39,6 +39,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 4291ea47f77752848e31341019e9be98f59526df Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Fri, 16 Jun 2017 15:43:21 +0200 Subject: [PATCH 51/64] Journal: Don't use a ._ path if it won't work #5633 When synchronizing a folder on a samba share, creating files that begin with ._ is often forbidden. This prevented the client from creating its ._sync_abcdef.db file. Now, it'll check whether the preferred filename is creatable, and if it isn't it'll use .sync_abcdef.db instead. The disadvantage is that this alternative path won't be ignored by older clients - that was the reason for the ._ prefix. --- csync/src/csync_exclude.c | 5 +++ csync/tests/csync_tests/check_csync_exclude.c | 11 ++++- src/cmd/cmd.cpp | 2 +- src/gui/folder.cpp | 2 +- src/gui/folderman.cpp | 15 ++++++- src/gui/folderwatcher_linux.cpp | 3 +- src/libsync/syncjournaldb.cpp | 40 ++++++++++++++++++- src/libsync/syncjournaldb.h | 3 +- 8 files changed, 73 insertions(+), 8 deletions(-) diff --git a/csync/src/csync_exclude.c b/csync/src/csync_exclude.c index e125b33462..88dd61e750 100644 --- a/csync/src/csync_exclude.c +++ b/csync/src/csync_exclude.c @@ -235,6 +235,11 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch match = CSYNC_FILE_SILENTLY_EXCLUDED; goto out; } + rc = csync_fnmatch(".sync_*.db*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } rc = csync_fnmatch(".csync_journal.db*", bname, 0); if (rc == 0) { match = CSYNC_FILE_SILENTLY_EXCLUDED; diff --git a/csync/tests/csync_tests/check_csync_exclude.c b/csync/tests/csync_tests/check_csync_exclude.c index e7af73c67f..bd4813c5ed 100644 --- a/csync/tests/csync_tests/check_csync_exclude.c +++ b/csync/tests/csync_tests/check_csync_exclude.c @@ -157,7 +157,16 @@ static void check_csync_excluded(void **state) assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE); assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); - + + rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); + rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); + rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); + rc = csync_excluded_no_ctx(csync->excludes, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED); + /* pattern ]*.directory - ignore and remove */ rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE); diff --git a/src/cmd/cmd.cpp b/src/cmd/cmd.cpp index 5421b23143..152f249962 100644 --- a/src/cmd/cmd.cpp +++ b/src/cmd/cmd.cpp @@ -469,7 +469,7 @@ restart_sync: } Cmd cmd; - QString dbPath = options.source_dir + SyncJournalDb::makeDbName(credentialFreeUrl, folder, user); + QString dbPath = options.source_dir + SyncJournalDb::makeDbName(options.source_dir, credentialFreeUrl, folder, user); SyncJournalDb db(dbPath); if (!selectiveSyncList.empty()) { diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 83ed5c531e..7e2d12b1ca 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -1003,7 +1003,7 @@ QString FolderDefinition::absoluteJournalPath() const QString FolderDefinition::defaultJournalPath(AccountPtr account) { - return SyncJournalDb::makeDbName(account->url(), targetPath, account->credentials()->user()); + return SyncJournalDb::makeDbName(localPath, account->url(), targetPath, account->credentials()->user()); } } // namespace OCC diff --git a/src/gui/folderman.cpp b/src/gui/folderman.cpp index 1a230a28ca..cb0fa90b53 100644 --- a/src/gui/folderman.cpp +++ b/src/gui/folderman.cpp @@ -235,11 +235,22 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account, foreach (const auto& folderAlias, settings.childGroups()) { FolderDefinition folderDefinition; if (FolderDefinition::load(settings, folderAlias, &folderDefinition)) { + auto defaultJournalPath = folderDefinition.defaultJournalPath(account->account()); + // Migration: Old settings don't have journalPath if (folderDefinition.journalPath.isEmpty()) { - folderDefinition.journalPath = folderDefinition.defaultJournalPath(account->account()); + folderDefinition.journalPath = defaultJournalPath; } - folderDefinition.defaultJournalPath(account->account()); + + // Migration: ._ files sometimes don't work + // So if the configured journalPath is the default one ("._sync_*.db") + // but the current default doesn't have the underscore, switch to the + // new default. See SyncJournalDb::makeDbName(). + if (folderDefinition.journalPath.startsWith("._sync_") + && defaultJournalPath.startsWith(".sync_")) { + folderDefinition.journalPath = defaultJournalPath; + } + // Migration: If an old db is found, move it to the new name. if (backwardsCompatible) { SyncJournalDb::maybeMigrateDb(folderDefinition.localPath, folderDefinition.absoluteJournalPath()); diff --git a/src/gui/folderwatcher_linux.cpp b/src/gui/folderwatcher_linux.cpp index c8024c00b4..d647f65959 100644 --- a/src/gui/folderwatcher_linux.cpp +++ b/src/gui/folderwatcher_linux.cpp @@ -171,7 +171,8 @@ void FolderWatcherPrivate::slotReceivedNotification(int fd) // qDebug() << Q_FUNC_INFO << event->name; if (fileName.startsWith("._sync_") || fileName.startsWith(".csync_journal.db") || - fileName.startsWith(".owncloudsync.log")) { + fileName.startsWith(".owncloudsync.log") || + fileName.startsWith(".sync_")) { // qDebug() << "ignore journal"; } else { const QString p = _watches[event->wd] + '/' + fileName; diff --git a/src/libsync/syncjournaldb.cpp b/src/libsync/syncjournaldb.cpp index 43ef9b37aa..c6c4a9cd5b 100644 --- a/src/libsync/syncjournaldb.cpp +++ b/src/libsync/syncjournaldb.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "ownsql.h" @@ -41,7 +42,8 @@ SyncJournalDb::SyncJournalDb(const QString& dbFilePath, QObject *parent) : } -QString SyncJournalDb::makeDbName(const QUrl& remoteUrl, +QString SyncJournalDb::makeDbName(const QString& localPath, + const QUrl& remoteUrl, const QString& remotePath, const QString& user) { @@ -56,6 +58,42 @@ QString SyncJournalDb::makeDbName(const QUrl& remoteUrl, journalPath.append( ba.left(6).toHex() ); journalPath.append(".db"); + // If the journal doesn't exist and we can't create a file + // at that location, try again with a journal name that doesn't + // have the ._ prefix. + // + // The disadvantage of that filename is that it will only be ignored + // by client versions >2.3.2. + // + // See #5633: "._*" is often forbidden on samba shared folders. + + // If it exists already, the path is clearly usable + QFile file(QDir(localPath).filePath(journalPath)); + if (file.exists()) { + return journalPath; + } + + // Try to create a file there + if (file.open(QIODevice::ReadWrite)) { + // Ok, all good. + file.close(); + file.remove(); + return journalPath; + } + + // Can we create it if we drop the underscore? + QString alternateJournalPath = journalPath.mid(2).prepend("."); + QFile file2(QDir(localPath).filePath(alternateJournalPath)); + if (file2.open(QIODevice::ReadWrite)) { + // The alternative worked, use it + qDebug() << "Using alternate database path" << alternateJournalPath; + file2.close(); + file2.remove(); + return alternateJournalPath; + } + + // Neither worked, just keep the original and throw errors later + qDebug() << "Could not find a writable database path" << file.fileName(); return journalPath; } diff --git a/src/libsync/syncjournaldb.h b/src/libsync/syncjournaldb.h index 72db1c4631..37df8c81ea 100644 --- a/src/libsync/syncjournaldb.h +++ b/src/libsync/syncjournaldb.h @@ -41,7 +41,8 @@ public: virtual ~SyncJournalDb(); /// Create a journal path for a specific configuration - static QString makeDbName(const QUrl& remoteUrl, + static QString makeDbName(const QString& localPath, + const QUrl& remoteUrl, const QString& remotePath, const QString& user); From 1e78a14f1aa6114ac448b961b663f1458473c99c Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 19 Jun 2017 10:48:19 +0200 Subject: [PATCH 52/64] Ignore ui: Add the sync journal patterns #5844 The ignore patterns for the journal files are hardcoded. Add them to the UI to make them discoverable. --- src/gui/ignorelisteditor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/ignorelisteditor.cpp b/src/gui/ignorelisteditor.cpp index d21cd0d875..1d124d1d6a 100644 --- a/src/gui/ignorelisteditor.cpp +++ b/src/gui/ignorelisteditor.cpp @@ -48,6 +48,9 @@ IgnoreListEditor::IgnoreListEditor(QWidget *parent) : "and cannot be modified in this view.") .arg(QDir::toNativeSeparators(cfgFile.excludeFile(ConfigFile::SystemScope))); + addPattern(".csync_journal.db*", /*deletable=*/false, /*readonly=*/true); + addPattern("._sync_*.db*", /*deletable=*/false, /*readonly=*/true); + addPattern(".sync_*.db*", /*deletable=*/false, /*readonly=*/true); readIgnoreFile(cfgFile.excludeFile(ConfigFile::SystemScope), true); readIgnoreFile(cfgFile.excludeFile(ConfigFile::UserScope), false); From 949e8e5f514027c8981fb623a8ee5a0061c70b25 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Wed, 21 Jun 2017 02:22:08 +0200 Subject: [PATCH 53/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 ++ translations/client_ca.ts | 52 ++++++++++++++++---------------- translations/client_cs.ts | 52 ++++++++++++++++---------------- translations/client_de.ts | 52 ++++++++++++++++---------------- translations/client_el.ts | 52 ++++++++++++++++---------------- translations/client_en.ts | 52 ++++++++++++++++---------------- translations/client_es.ts | 52 ++++++++++++++++---------------- translations/client_es_AR.ts | 52 ++++++++++++++++---------------- translations/client_et.ts | 52 ++++++++++++++++---------------- translations/client_eu.ts | 52 ++++++++++++++++---------------- translations/client_fa.ts | 52 ++++++++++++++++---------------- translations/client_fi.ts | 52 ++++++++++++++++---------------- translations/client_fr.ts | 52 ++++++++++++++++---------------- translations/client_gl.ts | 52 ++++++++++++++++---------------- translations/client_hu.ts | 52 ++++++++++++++++---------------- translations/client_it.ts | 52 ++++++++++++++++---------------- translations/client_ja.ts | 52 ++++++++++++++++---------------- translations/client_nb_NO.ts | 52 ++++++++++++++++---------------- translations/client_nl.ts | 52 ++++++++++++++++---------------- translations/client_pl.ts | 52 ++++++++++++++++---------------- translations/client_pt.ts | 52 ++++++++++++++++---------------- translations/client_pt_BR.ts | 58 ++++++++++++++++++------------------ translations/client_ru.ts | 52 ++++++++++++++++---------------- translations/client_sk.ts | 52 ++++++++++++++++---------------- translations/client_sl.ts | 52 ++++++++++++++++---------------- translations/client_sr.ts | 52 ++++++++++++++++---------------- translations/client_sv.ts | 52 ++++++++++++++++---------------- translations/client_th.ts | 52 ++++++++++++++++---------------- translations/client_tr.ts | 52 ++++++++++++++++---------------- translations/client_uk.ts | 52 ++++++++++++++++---------------- translations/client_zh_CN.ts | 52 ++++++++++++++++---------------- translations/client_zh_TW.ts | 52 ++++++++++++++++---------------- 32 files changed, 812 insertions(+), 809 deletions(-) diff --git a/mirall.desktop.in b/mirall.desktop.in index 65309df6d5..7dc441ec21 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -42,6 +42,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion diff --git a/translations/client_ca.ts b/translations/client_ca.ts index 4262da544d..dce4d38608 100644 --- a/translations/client_ca.ts +++ b/translations/client_ca.ts @@ -807,112 +807,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state No es pot restablir l'estat de la carpeta - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. S'ha trobat un diari de sincronització antic '%1', però no s'ha pogut eliminar. Assegureu-vos que no hi ha cap aplicació que actualment en faci ús. - + (backup) (copia de seguretat) - + (backup %1) (copia de seguretat %1) - + Undefined State. Estat indefinit. - + Waiting to start syncing. S'està esperant per començar a sincronitzar. - + Preparing for sync. S'està preparant per la sincronització. - + Sync is running. S'està sincronitzant. - + Last Sync was successful. La darrera sincronització va ser correcta. - + Last Sync was successful, but with warnings on individual files. La última sincronització ha estat un èxit, però amb avisos en fitxers individuals. - + Setup Error. Error de configuració. - + User Abort. Cancel·la usuari. - + Sync is paused. La sincronització està en pausa. - + %1 (Sync is paused) %1 (Sync està pausat) - + No valid folder selected! No s'ha seleccionat cap directori vàlid! - + The selected path is not a folder! La ruta seleccionada no és un directori! - + You have no permission to write to the selected folder! No teniu permisos per escriure en la carpeta seleccionada! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1345,22 +1345,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Els elements que poden ser eliminats s'eliminaran si impedeixen que una carpeta sigui eliminada. Això és útil per les metadades. - + Could not open file No s'ha pogut obrir el fitxer - + Cannot write changes to '%1'. No es poden desar els canvis a '%1'. - + Add Ignore Pattern Afegeix una plantilla per ignorar - + Add a new ignore pattern: Afegeix una nova plantilla d'ignorats: diff --git a/translations/client_cs.ts b/translations/client_cs.ts index a7e5c0de86..3c2eb0519f 100644 --- a/translations/client_cs.ts +++ b/translations/client_cs.ts @@ -810,112 +810,112 @@ Pokračováním v synchronizaci způsobí přepsání všech vašich souborů st OCC::FolderMan - + Could not reset folder state Nelze obnovit stav adresáře - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Byl nalezen starý záznam synchronizace '%1', ale nebylo možné jej odebrat. Ujistěte se, že není aktuálně používán jinou aplikací. - + (backup) (záloha) - + (backup %1) (záloha %1) - + Undefined State. Nedefinovaný stav. - + Waiting to start syncing. Čeká na spuštění synchronizace. - + Preparing for sync. Příprava na synchronizaci. - + Sync is running. Synchronizace probíhá. - + Last Sync was successful. Poslední synchronizace byla úspěšná. - + Last Sync was successful, but with warnings on individual files. Poslední synchronizace byla úspěšná, ale s varováním u některých souborů - + Setup Error. Chyba nastavení. - + User Abort. Zrušení uživatelem. - + Sync is paused. Synchronizace pozastavena. - + %1 (Sync is paused) %1 (Synchronizace je pozastavena) - + No valid folder selected! Nebyl vybrán platný adresář! - + The selected path is not a folder! Vybraná cesta nevede do adresáře! - + You have no permission to write to the selected folder! Nemáte oprávnění pro zápis do zvoleného adresáře! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Místní složka %1 obsahuje symbolický odkaz. Cílový odkaz obsahuje již synchronizované složky. Vyberte si prosím jinou! - + There is already a sync from the server to this local folder. Please pick another local folder! Ze serveru se do tohoto umístění již synchronizuje. Prosím zvolte jinou místní složku! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Místní adresář %1 již obsahuje podadresář použitý pro synchronizaci odesílání. Zvolte prosím jiný! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Místní adresář %1 je již obsažen ve adresáři použitém pro synchronizaci. Vyberte prosím jiný! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Místní adresář %1 je symbolickým obsahem. Cíl odkazu je již obsažen v adresáři použitém pro synchronizaci. Vyberte prosím jiný! @@ -1348,22 +1348,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Položky u kterých je povoleno smazání budou vymazány, pokud by bránily odstranění adresáře. Toto je užitečné pro metadata.
- + Could not open file Nepodařilo se otevřít soubor - + Cannot write changes to '%1'. Nelze zapsat změny do '%1'. - + Add Ignore Pattern Přidat masku ignorovaných - + Add a new ignore pattern: Přidat novou masku ignorovaných souborů: diff --git a/translations/client_de.ts b/translations/client_de.ts index 9406716cbd..5b3b13befd 100644 --- a/translations/client_de.ts +++ b/translations/client_de.ts @@ -812,112 +812,112 @@ Wenn diese Synchronisation fortgesetzt wird, werden Dateien eventuell von älter OCC::FolderMan - + Could not reset folder state Konnte Ordner-Zustand nicht zurücksetzen - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Ein altes Synchronisations-Journal '%1' wurde gefunden, konnte jedoch nicht entfernt werden. Bitte stellen Sie sicher, dass keine Anwendung es verwendet. - + (backup) (Sicherung) - + (backup %1) (Sicherung %1) - + Undefined State. Undefinierter Zustand. - + Waiting to start syncing. Wartet auf Beginn der Synchronistation - + Preparing for sync. Synchronisation wird vorbereitet. - + Sync is running. Synchronisation läuft. - + Last Sync was successful. Die letzte Synchronisation war erfolgreich. - + Last Sync was successful, but with warnings on individual files. Letzte Synchronisation war erfolgreich, aber mit Warnungen für einzelne Dateien. - + Setup Error. Installationsfehler. - + User Abort. Benutzer-Abbruch - + Sync is paused. Synchronisation wurde angehalten. - + %1 (Sync is paused) %1 (Synchronisation ist pausiert) - + No valid folder selected! Kein gültige Ordner gewählt! - + The selected path is not a folder! Der gewählte Pfad ist kein Ordner! - + You have no permission to write to the selected folder! Sie haben keine Schreibberechtigung für den ausgewählten Ordner! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Der lokale Ordner %1 beinhaltet einen symbolischer Link. Das Ziel des Links beinhaltet bereits einen synchronisierten Ordner. Bitte wählen Sie einen anderen lokalen Ordner aus! - + There is already a sync from the server to this local folder. Please pick another local folder! Es exisitiert bereits eine Synchronisation vom Server zu diesem lokalen Ordner. Bitte wählen Sie ein anderes lokales Verzeichnis! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Der lokale Ordner %1 liegt innerhalb eines synchronisierten Ordners. Bitte wählen Sie einen anderen aus! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Der lokale Ordner %1 liegt in einem Ordner, der bereits synchronisiert wird. Bitte wählen Sie einen anderen aus! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Der lokale Ordner %1 ist ein symbolischer Link. Das Ziel des Links liegt in einem Ordner, der schon synchronisiert wird. Bitte wählen Sie einen anderen aus! @@ -1350,22 +1350,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Objekte, bei denen Löschen erlaubt ist, werden gelöscht, wenn sie die Löschung eines Ordners verhindern würden. Das ist für Metadaten nützlich.
- + Could not open file Datei konnte nicht geöffnet werden - + Cannot write changes to '%1'. Konnte Änderungen nicht in '%1' schreiben. - + Add Ignore Pattern Ignoriermuster hinzufügen - + Add a new ignore pattern: Neues Ignoriermuster hinzufügen: diff --git a/translations/client_el.ts b/translations/client_el.ts index 9747282ec1..bac0620b61 100644 --- a/translations/client_el.ts +++ b/translations/client_el.ts @@ -812,112 +812,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Δεν ήταν δυνατό να επαναφερθεί η κατάσταση του φακέλου - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Βρέθηκε ένα παλαιότερο αρχείο συγχρονισμού '%1', αλλά δεν μπόρεσε να αφαιρεθεί. Παρακαλώ βεβαιωθείτε ότι καμμία εφαρμογή δεν το χρησιμοποιεί αυτή τη στιγμή. - + (backup) (αντίγραφο ασφαλείας) - + (backup %1) (αντίγραοφ ασφαλέιας %1) - + Undefined State. Απροσδιόριστη Κατάσταση. - + Waiting to start syncing. Αναμονή έναρξης συγχρονισμού. - + Preparing for sync. Προετοιμασία για συγχρονισμό. - + Sync is running. Ο συγχρονισμός εκτελείται. - + Last Sync was successful. Ο τελευταίος συγχρονισμός ήταν επιτυχής. - + Last Sync was successful, but with warnings on individual files. Ο τελευταίος συγχρονισμός ήταν επιτυχής, αλλά υπήρχαν προειδοποιήσεις σε συγκεκριμένα αρχεία. - + Setup Error. Σφάλμα Ρύθμισης. - + User Abort. Ματαίωση από Χρήστη. - + Sync is paused. Παύση συγχρονισμού. - + %1 (Sync is paused) %1 (Παύση συγχρονισμού) - + No valid folder selected! Δεν επιλέχθηκε έγκυρος φάκελος! - + The selected path is not a folder! Η επιλεγμένη διαδρομή δεν είναι φάκελος! - + You have no permission to write to the selected folder! Δεν έχετε δικαιώματα εγγραφής στον επιλεγμένο φάκελο! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Ο τοπικός φάκελος% 1 περιέχει έναν συμβολικό σύνδεσμο. Ο στόχος συνδέσμου περιέχει έναν ήδη συγχρονισμένο φάκελο.Παρακαλώ επιλέξτε ένα άλλο! - + There is already a sync from the server to this local folder. Please pick another local folder! Υπάρχει ήδη συγχρονισμός από το διακομιστή σε αυτόν τον τοπικό φάκελο. Επιλέξτε έναν άλλο τοπικό φάκελο! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Ο τοπικός φάκελος %1 περιέχει ήδη ένα φάκελο που χρησιμοποιείται σε μια σύνδεση συγχρονισμού φακέλου. Παρακαλώ επιλέξτε άλλον! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Ο τοπικός φάκελος %1 περιέχεται ήδη σε φάκελο που χρησιμοποιείται σε μια σύνδεση συγχρονισμού. Παρακαλώ επιλέξτε άλλον! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Ο τοπικός φάκελος %1 είναι συμβολικός σύνδεσμος. Ο σύνδεσμος που παραπέμπει περιέχεται ήδη σε φάκελο που βρίσκεται σε συγχρονισμό. Παρακαλώ επιλέξτε άλλον! @@ -1350,22 +1350,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Τα στοιχεία όπου επιτρέπεται η διαγραφή θα διαγράφονται εάν εμποδίζουν την αφαίρεση ενός φακέλου αρχείων. Αυτό είναι χρήσιμο για μετα-δεδομένα.
- + Could not open file Αδυναμία ανοίγματος αρχείου - + Cannot write changes to '%1'. Αδυναμία εγγραφής αλλαγών στο '%1'. - + Add Ignore Pattern Προσθήκη Προτύπου Αγνόησης - + Add a new ignore pattern: Προσθήκη νέου προτύπου αγνόησης: diff --git a/translations/client_en.ts b/translations/client_en.ts index e2646f23c3..b6a2146eae 100644 --- a/translations/client_en.ts +++ b/translations/client_en.ts @@ -832,112 +832,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. - + (backup) - + (backup %1) - + Undefined State. - + Waiting to start syncing. - + Preparing for sync. - + Sync is running. - + Last Sync was successful. - + Last Sync was successful, but with warnings on individual files. - + Setup Error. - + User Abort. - + Sync is paused. - + %1 (Sync is paused) - + No valid folder selected! - + The selected path is not a folder! - + You have no permission to write to the selected folder! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1371,22 +1371,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from
- + Could not open file - + Cannot write changes to '%1'. - + Add Ignore Pattern - + Add a new ignore pattern: diff --git a/translations/client_es.ts b/translations/client_es.ts index f696e4fd25..97b7e559ba 100644 --- a/translations/client_es.ts +++ b/translations/client_es.ts @@ -812,112 +812,112 @@ Si continua con la sincronización todos los archivos serán remplazados por su OCC::FolderMan - + Could not reset folder state No se ha podido restablecer el estado de la carpeta - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Se ha encontrado un antiguo registro de sincronización '%1'; pero no se ha podido eliminar. Por favor, asegúrese de que ninguna aplicación la esté utilizando. - + (backup) (copia de seguridad) - + (backup %1) (copia de seguridad %1) - + Undefined State. Estado no definido. - + Waiting to start syncing. Esperando para comenzar la sincronización. - + Preparing for sync. Preparándose para sincronizar. - + Sync is running. Sincronización en funcionamiento. - + Last Sync was successful. La última sincronización se ha realizado con éxito. - + Last Sync was successful, but with warnings on individual files. La última sincronización salió bien; pero hay advertencias para archivos individuales. - + Setup Error. Error de configuración. - + User Abort. Interrumpido por el usuario. - + Sync is paused. La sincronización está en pausa. - + %1 (Sync is paused) %1 (Sincronización en pausa) - + No valid folder selected! ¡La carpeta seleccionada no es válida! - + The selected path is not a folder! ¡La ruta seleccionada no es un directorio! - + You have no permission to write to the selected folder! ¡Usted no tiene permiso para escribir en la carpeta seleccionada! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! El directorio local %1 es un enlace simbólico. El objetivo del enlace ya contiene un directorio usado en una conexión de sincronización de directorios. Por favor, elija otro. - + There is already a sync from the server to this local folder. Please pick another local folder! Ya existe una tarea de sincronización entre el servidor y esta carpeta. Por favor elija otra carpeta local. - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! El directorio local %1 ya contiene un directorio usado en una conexión de sincronización de directorios. Por favor, elija otro. - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! El directorio local %1 está dentro de un directorio usado en una conexión de sincronización de directorios. Por favor, elija otro. - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! El directorio local %1 es un enlace simbólico. El objetivo está incluido en un directorio usado en una conexión de sincronización de directorios. Por favor, elija otro. @@ -1350,22 +1350,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Los elementos cuya eliminación está permitida serán eliminados si impiden que un directorio sea eliminado. Esto es útil para sus metadatos.
- + Could not open file No se ha podido abrir el archivo - + Cannot write changes to '%1'. No se pueden guardar cambios en '%1'. - + Add Ignore Pattern Añadir patrón para ignorar - + Add a new ignore pattern: Añadir nuevo patrón para ignorar: diff --git a/translations/client_es_AR.ts b/translations/client_es_AR.ts index 98256d9e92..f0839b5d42 100644 --- a/translations/client_es_AR.ts +++ b/translations/client_es_AR.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state No se pudo - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Una antigua sincronización con journaling '%1' fue encontrada, pero no se pudo eliminar. Por favor, asegurate que ninguna aplicación la está utilizando. - + (backup) - + (backup %1) - + Undefined State. Estado no definido. - + Waiting to start syncing. - + Preparing for sync. Preparando la sincronización. - + Sync is running. Sincronización en funcionamiento. - + Last Sync was successful. La última sincronización fue exitosa. - + Last Sync was successful, but with warnings on individual files. El último Sync fue exitoso, pero hubo advertencias en archivos individuales. - + Setup Error. Error de configuración. - + User Abort. Interrumpir. - + Sync is paused. La sincronización está en pausa. - + %1 (Sync is paused) %1 (Sincronización en pausa) - + No valid folder selected! - + The selected path is not a folder! - + You have no permission to write to the selected folder! ¡No tenés permisos para escribir el directorio seleccionado! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from
- + Could not open file No se pudo abrir el archivo - + Cannot write changes to '%1'. No se pueden guardar cambios en '%1'. - + Add Ignore Pattern Agregar patrón a ignorar - + Add a new ignore pattern: Añadir nuevo patrón a ignorar: diff --git a/translations/client_et.ts b/translations/client_et.ts index 7d695e17ad..1e194a6058 100644 --- a/translations/client_et.ts +++ b/translations/client_et.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Ei suutnud tühistada kataloogi staatust - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Leiti vana sünkroniseeringu zurnaal '%1', kuid selle eemaldamine ebaõnnenstus. Palun veendu, et seda kasutaks ükski programm. - + (backup) (varukoopia) - + (backup %1) (varukoopia %1) - + Undefined State. Määramata staatus. - + Waiting to start syncing. Oodatakse sünkroonimise alustamist. - + Preparing for sync. Valmistun sünkroniseerima. - + Sync is running. Sünkroniseerimine on käimas. - + Last Sync was successful. Viimane sünkroniseerimine oli edukas. - + Last Sync was successful, but with warnings on individual files. Viimane sünkroniseering oli edukas, kuid mõned failid põhjustasid tõrkeid. - + Setup Error. Seadistamise viga. - + User Abort. Kasutaja tühistamine. - + Sync is paused. Sünkroniseerimine on peatatud. - + %1 (Sync is paused) %1 (Sünkroniseerimine on peatatud) - + No valid folder selected! Sobilikku kausta pole valitud! - + The selected path is not a folder! Valitud asukoht pole kaust! - + You have no permission to write to the selected folder! Sul puuduvad õigused valitud kataloogi kirjutamiseks! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from
- + Could not open file Ei suutunud avada faili - + Cannot write changes to '%1'. Ei saa kirjutada muudatusi '%1'. - + Add Ignore Pattern Lisa ignoreerimise muster - + Add a new ignore pattern: Lisa uus ignoreerimise muster: diff --git a/translations/client_eu.ts b/translations/client_eu.ts index 53cedf8ed8..73e5d44a24 100644 --- a/translations/client_eu.ts +++ b/translations/client_eu.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Ezin izan da karpetaren egoera berrezarri - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Aurkitu da '%1' sinkronizazio erregistro zaharra, baina ezin da ezabatu. Ziurtatu aplikaziorik ez dela erabiltzen ari. - + (backup) - + (backup %1) - + Undefined State. Definitu gabeko egoera. - + Waiting to start syncing. Itxoiten sinkronizazioa hasteko. - + Preparing for sync. Sinkronizazioa prestatzen. - + Sync is running. Sinkronizazioa martxan da. - + Last Sync was successful. Azkeneko sinkronizazioa ongi burutu zen. - + Last Sync was successful, but with warnings on individual files. Azkenengo sinkronizazioa ongi burutu zen, baina banakako fitxategi batzuetan abisuak egon dira. - + Setup Error. Konfigurazio errorea. - + User Abort. Erabiltzaileak bertan behera utzi. - + Sync is paused. Sinkronizazioa pausatuta dago. - + %1 (Sync is paused) %1 (Sinkronizazioa pausatuta dago) - + No valid folder selected! Ez da karpeta egokirik hautatu! - + The selected path is not a folder! Hautatutako bidea ez da karpeta bat! - + You have no permission to write to the selected folder! Ez daukazu hautatutako karpetan idazteko baimenik! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1341,22 +1341,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Ezabatzeko baimena duten itemak ezabatuko dira hauek karpeta bat ezabatzea uzten ez badute. Hau meta datuentzat interesgarria da.
- + Could not open file Ezin izan da fitxategia ireki - + Cannot write changes to '%1'. Ezin izan dira aldaketa idatzi hemen '%1'. - + Add Ignore Pattern Gehitu Baztertzeko Eredua - + Add a new ignore pattern: Gehitu baztertzeko eredu berria: diff --git a/translations/client_fa.ts b/translations/client_fa.ts index 53fba3ebc6..cafd7cfadc 100644 --- a/translations/client_fa.ts +++ b/translations/client_fa.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state نمی تواند حالت پوشه را تنظیم مجدد کند - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. - + (backup) (backup) - + (backup %1) (پشتیبان %1) - + Undefined State. موقعیت تعریف نشده - + Waiting to start syncing. - + Preparing for sync. آماده سازی برای همگام سازی کردن. - + Sync is running. همگام سازی در حال اجراست - + Last Sync was successful. آخرین همگام سازی موفقیت آمیز بود - + Last Sync was successful, but with warnings on individual files. - + Setup Error. خطا در پیکر بندی. - + User Abort. خارج کردن کاربر. - + Sync is paused. همگام سازی فعلا متوقف شده است - + %1 (Sync is paused) %1 (همگام‌سازی موقتا متوقف شده است) - + No valid folder selected! هیچ پوشه‌ی معتبری انتخاب نشده است! - + The selected path is not a folder! - + You have no permission to write to the selected folder! شما اجازه نوشتن در پوشه های انتخاب شده را ندارید! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from
- + Could not open file امکان باز کردن فایل وجود ندارد - + Cannot write changes to '%1'. - + Add Ignore Pattern - + Add a new ignore pattern: diff --git a/translations/client_fi.ts b/translations/client_fi.ts index ca263a3fcc..08064209e8 100644 --- a/translations/client_fi.ts +++ b/translations/client_fi.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Kansion tilaa ei voitu alustaa - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. - + (backup) (varmuuskopio) - + (backup %1) (varmuuskopio %1) - + Undefined State. Määrittelemätön tila. - + Waiting to start syncing. Odotetaan synkronoinnin aloitusta. - + Preparing for sync. Valmistellaan synkronointia. - + Sync is running. Synkronointi on meneillään. - + Last Sync was successful. Viimeisin synkronointi suoritettiin onnistuneesti. - + Last Sync was successful, but with warnings on individual files. Viimeisin synkronointi onnistui, mutta yksittäisten tiedostojen kanssa ilmeni varoituksia. - + Setup Error. Asetusvirhe. - + User Abort. - + Sync is paused. Synkronointi on keskeytetty. - + %1 (Sync is paused) %1 (Synkronointi on keskeytetty) - + No valid folder selected! Kelvollista kansiota ei ole valittu! - + The selected path is not a folder! Valittu polku ei ole kansio! - + You have no permission to write to the selected folder! Sinulla ei ole kirjoitusoikeutta valittuun kansioon! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Paikallinen kansio %1 sisältää kansion, jota käytetään kansion synkronointiyhteydessä. Valitse toinen kansio! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1341,22 +1341,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Kohteet, joiden poisto on sallittu, poistetaan, jos ne estävät kansion poistamisen. Tämä on hyödyllistä metatietojen osalta.
- + Could not open file Tiedoston avaaminen ei onnistunut - + Cannot write changes to '%1'. Muutoksien kirjoittaminen kohteeseen '%1' epäonnistui. - + Add Ignore Pattern Lisää ohituskaava - + Add a new ignore pattern: Lisää uusi ohituskaava: diff --git a/translations/client_fr.ts b/translations/client_fr.ts index a9e38307c8..c570e49b41 100644 --- a/translations/client_fr.ts +++ b/translations/client_fr.ts @@ -813,112 +813,112 @@ Continuer la synchronisation comme d'habitude fera en sorte que tous les fi OCC::FolderMan - + Could not reset folder state Impossible de réinitialiser l'état du dossier - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Un ancien fichier journal '%1' a été trouvé, mais ne peut être supprimé. Veuillez vous assurer qu’aucune application ne l'utilise en ce moment. - + (backup) (sauvegarde) - + (backup %1) (sauvegarde %1) - + Undefined State. Statut indéfini. - + Waiting to start syncing. En attente de synchronisation. - + Preparing for sync. Préparation de la synchronisation. - + Sync is running. Synchronisation en cours - + Last Sync was successful. Synchronisation terminée avec succès - + Last Sync was successful, but with warnings on individual files. Synchronisation terminée avec des avertissements pour certains fichiers - + Setup Error. Erreur d'installation. - + User Abort. Abandon par l'utilisateur. - + Sync is paused. La synchronisation est en pause. - + %1 (Sync is paused) %1 (Synchronisation en pause) - + No valid folder selected! Aucun dossier valable sélectionné ! - + The selected path is not a folder! Le chemin sélectionné n'est pas un dossier ! - + You have no permission to write to the selected folder! Vous n'avez pas la permission d'écrire dans le dossier sélectionné ! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Le dossier local %1 contient un lien symbolique. La cible du lien contient un dossier déjà synchronisé. Veuillez en choisir un autre ! - + There is already a sync from the server to this local folder. Please pick another local folder! Il y a déjà une synchronisation depuis le serveur vers ce dossier local. Merci de choisir un autre dossier local ! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Le dossier local %1 contient un dossier déjà utilisé pour une synchronisation de dossiers. Veuillez en choisir un autre ! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Le dossier local %1 se trouve dans un dossier déjà configuré pour une synchronisation de dossier. Veuillez en choisir un autre ! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Le dossier local %1 est un lien symbolique. Le dossier vers lequel le lien pointe est inclus dans un dossier déjà configuré pour une synchronisation de dossier. Veuillez en choisir un autre ! @@ -1351,22 +1351,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from L'option "Autoriser suppression" permet de ne pas bloquer la suppression d'un dossier. C'est utile pour les fichiers de méta-données. - + Could not open file Impossible d'ouvrir le fichier - + Cannot write changes to '%1'. Impossible d'écrire les modifications sur '%1'. - + Add Ignore Pattern Ajouter un motif d'exclusion - + Add a new ignore pattern: Ajoutez un nouveau motif d'exclusion : diff --git a/translations/client_gl.ts b/translations/client_gl.ts index 07ddb5b8a8..84643b388b 100644 --- a/translations/client_gl.ts +++ b/translations/client_gl.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Non foi posíbel restabelecer o estado do cartafol - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Atopouse un rexistro de sincronización antigo en «%1» máis non pode ser retirado. Asegúrese de que non o está a usar ningunha aplicación. - + (backup) (copia de seguranza) - + (backup %1) (copia de seguranza %1) - + Undefined State. Estado sen definir. - + Waiting to start syncing. - + Preparing for sync. Preparando para sincronizar. - + Sync is running. Estase sincronizando. - + Last Sync was successful. A última sincronización fíxose correctamente. - + Last Sync was successful, but with warnings on individual files. A última sincronización fíxose correctamente, mais con algún aviso en ficheiros individuais. - + Setup Error. Erro de configuración. - + User Abort. Interrompido polo usuario. - + Sync is paused. Sincronización en pausa. - + %1 (Sync is paused) %1 (sincronización en pausa) - + No valid folder selected! Non seleccionou ningún cartafol correcto! - + The selected path is not a folder! - + You have no permission to write to the selected folder! Vostede non ten permiso para escribir neste cartafol! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from - + Could not open file Non foi posíbel abrir o ficheiro - + Cannot write changes to '%1'. Non é posíbel escribir os cambios en «%1». - + Add Ignore Pattern Engadir o patrón a ignorar - + Add a new ignore pattern: Engadir un novo patrón a ignorar: diff --git a/translations/client_hu.ts b/translations/client_hu.ts index 8972b28a6f..192694b89b 100644 --- a/translations/client_hu.ts +++ b/translations/client_hu.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. - + (backup) (biztonsági mentés) - + (backup %1) (biztonsági mentés: %1) - + Undefined State. Ismeretlen állapot. - + Waiting to start syncing. Várakozás a szinkronizálás elindítására. - + Preparing for sync. Előkészítés szinkronizációhoz. - + Sync is running. Szinkronizálás fut. - + Last Sync was successful. Legutolsó szinkronizálás sikeres volt. - + Last Sync was successful, but with warnings on individual files. Az utolsó szinkronizáció sikeresen lefutott, de néhány figyelmeztetés van. - + Setup Error. Beállítás hiba. - + User Abort. Felhasználó megszakította. - + Sync is paused. Szinkronizálás megállítva. - + %1 (Sync is paused) %1 (szinkronizálás megállítva) - + No valid folder selected! Nincs érvényes könyvtár kiválasztva! - + The selected path is not a folder! A kiválasztott elérési út nem könyvtár! - + You have no permission to write to the selected folder! Nincs joga a kiválasztott könyvtár írásához! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from - + Could not open file Nem sikerült a fájl megnyitása - + Cannot write changes to '%1'. - + Add Ignore Pattern - + Add a new ignore pattern: diff --git a/translations/client_it.ts b/translations/client_it.ts index 762cec02bd..fc949e14a5 100644 --- a/translations/client_it.ts +++ b/translations/client_it.ts @@ -808,112 +808,112 @@ Se continui normalmente la sincronizzazione provocherai la sovrascrittura di tut OCC::FolderMan - + Could not reset folder state Impossibile ripristinare lo stato della cartella - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. È stato trovato un vecchio registro di sincronizzazione '%1', ma non può essere rimosso. Assicurati che nessuna applicazione lo stia utilizzando. - + (backup) (copia di sicurezza) - + (backup %1) (copia di sicurezza %1) - + Undefined State. Stato non definito. - + Waiting to start syncing. In attesa di iniziare la sincronizzazione. - + Preparing for sync. Preparazione della sincronizzazione. - + Sync is running. La sincronizzazione è in corso. - + Last Sync was successful. L'ultima sincronizzazione è stata completata correttamente. - + Last Sync was successful, but with warnings on individual files. Ultima sincronizzazione avvenuta, ma con avvisi relativi a singoli file. - + Setup Error. Errore di configurazione. - + User Abort. Interrotto dall'utente. - + Sync is paused. La sincronizzazione è sospesa. - + %1 (Sync is paused) %1 (La sincronizzazione è sospesa) - + No valid folder selected! Nessuna cartella valida selezionata! - + The selected path is not a folder! Il percorso selezionato non è una cartella! - + You have no permission to write to the selected folder! Non hai i permessi di scrittura per la cartella selezionata! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! La cartella locale %1 contiene un collegamento simbolico. La destinazione del collegamento contiene una cartella già sincronizzata. Selezionane un'altra! - + There is already a sync from the server to this local folder. Please pick another local folder! Esiste già una sincronizzazione dal server a questa cartella locale. Seleziona un'altra cartella locale! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! La cartella locale %1 contiene già una cartella utilizzata in una connessione di sincronizzazione delle cartelle. Selezionane un'altra! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! La cartella locale %1 è già contenuta in una cartella utilizzata in una connessione di sincronizzazione delle cartelle. Selezionane un'altra! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! La cartella locale %1 è un collegamento simbolico. La destinazione del collegamento è già contenuta in una cartella utilizzata in una connessione di sincronizzazione delle cartelle. Selezionane un'altra! @@ -1346,22 +1346,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Gli elementi per i quali è consentita l'eliminazione, saranno eliminati se impediscono la rimozione di una cartella. Utile per i metadati. - + Could not open file Impossibile aprire il file - + Cannot write changes to '%1'. Impossibile scrivere le modifiche in '%1'. - + Add Ignore Pattern Aggiungi modello Ignora - + Add a new ignore pattern: Aggiungi un nuovo modello di esclusione: diff --git a/translations/client_ja.ts b/translations/client_ja.ts index 119b9ccfda..d750ca1f24 100644 --- a/translations/client_ja.ts +++ b/translations/client_ja.ts @@ -810,112 +810,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state フォルダーの状態をリセットできませんでした - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. 古い同期ジャーナル '%1' が見つかりましたが、削除できませんでした。それを現在使用しているアプリケーションが存在しないか確認してください。 - + (backup) (バックアップ) - + (backup %1) (%1をバックアップ) - + Undefined State. 未定義の状態。 - + Waiting to start syncing. 同期開始を待機中 - + Preparing for sync. 同期の準備中。 - + Sync is running. 同期を実行中です。 - + Last Sync was successful. 最後の同期は成功しました。 - + Last Sync was successful, but with warnings on individual files. 最新の同期は成功しました。しかし、一部のファイルに問題がありました。 - + Setup Error. 設定エラー。 - + User Abort. ユーザーによる中止。 - + Sync is paused. 同期を一時停止しました。 - + %1 (Sync is paused) %1 (同期を一時停止) - + No valid folder selected! 有効なフォルダーが選択されていません! - + The selected path is not a folder! 指定のパスは、フォルダーではありません! - + You have no permission to write to the selected folder! 選択されたフォルダーに書き込み権限がありません - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! ローカルフォルダー %1 にはシンボリックリンクが含まれています。リンク先にはすでに同期されたフォルダーが含まれているため、別のフォルダーを選択してください! - + There is already a sync from the server to this local folder. Please pick another local folder! すでに同期されたフォルダーがあります。別のフォルダーを選択してください! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! ローカルフォルダー %1 にはすでに同期フォルダーとして利用されてるフォルダーを含んでいます。他のフォルダーを選択してください。 - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! ローカルフォルダー %1 には同期フォルダーとして利用されているフォルダーがあります。他のフォルダーを選択してください。 - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! ローカルフォルダー %1 には同期フォルダーとして利用されているフォルダーがあります。他のフォルダーを選択してください! @@ -1348,22 +1348,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from パターンによってディレクトリを削除から除外する場合は,パターンに含まれた項目も削除されます。例えばメタデータファイルに有用です。 - + Could not open file ファイルが開けませんでした - + Cannot write changes to '%1'. '%1'を更新できません。 - + Add Ignore Pattern 除外するファイルパターンを追加 - + Add a new ignore pattern: 除外するファイルパターンを新しく追加: diff --git a/translations/client_nb_NO.ts b/translations/client_nb_NO.ts index fb7e485e6a..76bd6db10e 100644 --- a/translations/client_nb_NO.ts +++ b/translations/client_nb_NO.ts @@ -811,112 +811,112 @@ Hvis synkroniseringen fortsetter som normalt, vil alle filene dine bli overskrev OCC::FolderMan - + Could not reset folder state Klarte ikke å tilbakestille mappetilstand - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. En gammel synkroniseringsjournal '%1' ble funnet men kunne ikke fjernes. Pass på at ingen applikasjoner bruker den. - + (backup) (sikkerhetskopi) - + (backup %1) (sikkerhetskopi %1) - + Undefined State. Udefinert tilstand. - + Waiting to start syncing. Venter på å starte synkronisering. - + Preparing for sync. Forbereder synkronisering. - + Sync is running. Synkronisering kjører. - + Last Sync was successful. Siste synkronisering var vellykket. - + Last Sync was successful, but with warnings on individual files. Siste synkronisering var vellykket, men med advarsler på enkelte filer. - + Setup Error. Feil med oppsett. - + User Abort. Brukeravbrudd. - + Sync is paused. Synkronisering er satt på pause. - + %1 (Sync is paused) %1 (Synkronisering er satt på pause) - + No valid folder selected! Ingen gyldig mappe valgt! - + The selected path is not a folder! Den valgte stien er ikke en mappe! - + You have no permission to write to the selected folder! Du har ikke skrivetilgang til den valgte mappen! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Den lokale mappen %1 inneholder en symbolsk lenke. Målet for lenken inneholder en mappe som allerede er synkronisert. Velg en annen mappe! - + There is already a sync from the server to this local folder. Please pick another local folder! Det er allerede en synkronisering fra serveren til denne lokale mappen. Velg en annen mappe! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Den lokale mappen %1 inneholder allerede en mappe brukt i en mappe-synkronisering. Velg en annen! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Den lokale mappen %1 er allerede en undermappe av en mappe brukt i en mappe-synkronisering. Velg en annen! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Den lokale mappen %1 er en symbolsk lenke. Målet for lenken er allerede en undermappe av en mappe brukt i en mappe-synkronisering. Velg en annen! @@ -1349,22 +1349,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Elementer hvor sletting er tillatt, vil bli slettet hvis de forhindrer fjerning av en mappe. Dette er hendig for metadata. - + Could not open file Klarte ikke å åpne fil - + Cannot write changes to '%1'. Kan ikke skrive endringer til '%1'. - + Add Ignore Pattern Nytt mønster - + Add a new ignore pattern: Legg til ignoreringsmønster: diff --git a/translations/client_nl.ts b/translations/client_nl.ts index 16dbaf1a46..d2e03afd6e 100644 --- a/translations/client_nl.ts +++ b/translations/client_nl.ts @@ -811,112 +811,112 @@ Doorgaan met deze synchronisatie overschrijft al uw bestanden door een eerdere v OCC::FolderMan - + Could not reset folder state Kan de beginstaat van de map niet terugzetten - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Een oud synchronisatieverslag '%1' is gevonden maar kan niet worden verwijderd. Zorg ervoor dat geen applicatie dit bestand gebruikt. - + (backup) (backup) - + (backup %1) (backup %1) - + Undefined State. Ongedefiniëerde staat - + Waiting to start syncing. In afwachting van synchronisatie. - + Preparing for sync. Synchronisatie wordt voorbereid - + Sync is running. Bezig met synchroniseren. - + Last Sync was successful. Laatste synchronisatie was geslaagd. - + Last Sync was successful, but with warnings on individual files. Laatste synchronisatie geslaagd, maar met waarschuwingen over individuele bestanden. - + Setup Error. Installatiefout. - + User Abort. Afgebroken door gebruiker. - + Sync is paused. Synchronisatie gepauzeerd. - + %1 (Sync is paused) %1 (Synchronisatie onderbroken) - + No valid folder selected! Geen geldige map geselecteerd! - + The selected path is not a folder! Het geselecteerde pad is geen map! - + You have no permission to write to the selected folder! U heeft geen permissie om te schrijven naar de geselecteerde map! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Lokale map %1 bevat een symbolische link. De doellink bevat een map die al is gesynchroniseerd. Kies een andere! - + There is already a sync from the server to this local folder. Please pick another local folder! Er wordt vanaf de server al naar deze lokale map gesynchroniseerd. Kies een andere lokale map! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Lokale map %1 bevat al een map die wordt gebruikt voor een mapsync verbinding. Kies een andere! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Lokale map %1 zit al in een map die wordt gebruikt voor een mapsync verbinding. Kies een andere! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Lokale map %1 is een symbolische link. De doellink zit al in een map die in een mapsync verbinding wordt gebruikt. Kies een andere! @@ -1354,22 +1354,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Onderdelen die gewist mogen worden worden verwijderd als ze voorkomen dat een map verdwijnt. Dit is nuttig voor metadata. - + Could not open file Kon het bestand niet openen - + Cannot write changes to '%1'. Er kunnen geen wijzigingen worden geschreven naar %1 - + Add Ignore Pattern Toevoegen negeerpatroon - + Add a new ignore pattern: Voeg nieuw negeerpatroon toe: diff --git a/translations/client_pl.ts b/translations/client_pl.ts index f0845f7571..e773f7c385 100644 --- a/translations/client_pl.ts +++ b/translations/client_pl.ts @@ -805,112 +805,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Nie udało się zresetować stanu folderu - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Stary sync journal '%1' został znaleziony, lecz nie mógł być usunięty. Proszę się upewnić, że żaden program go obecnie nie używa. - + (backup) (kopia zapasowa) - + (backup %1) (kopia zapasowa %1) - + Undefined State. Niezdefiniowany stan - + Waiting to start syncing. Poczekaj na rozpoczęcie synchronizacji. - + Preparing for sync. Przygotowuję do synchronizacji - + Sync is running. Synchronizacja w toku - + Last Sync was successful. Ostatnia synchronizacja zakończona powodzeniem. - + Last Sync was successful, but with warnings on individual files. Ostatnia synchronizacja udana, ale istnieją ostrzeżenia z pojedynczymi plikami. - + Setup Error. Błąd ustawień. - + User Abort. Użytkownik anulował. - + Sync is paused. Synchronizacja wstrzymana - + %1 (Sync is paused) %1 (Synchronizacja jest zatrzymana) - + No valid folder selected! Nie wybrano poprawnego folderu. - + The selected path is not a folder! Wybrana ścieżka nie jest katalogiem! - + You have no permission to write to the selected folder! Nie masz uprawnień, aby zapisywać w tym katalogu! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Lokalny folder %1 już zawiera folder użyty na potrzeby synchronizacji. Proszę wybrać inny folder lokalny. - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Lokalny folder %1 już zawiera folder użyty na potrzeby synchronizacji. Proszę wybrać inny folder lokalny. - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1343,22 +1343,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Pozycje, dla których usuwanie jest dozwolone zostaną usunięte, jeżeli uprawnienia katalogu dopuszczają usuwanie. - + Could not open file Nie można otworzyć plików - + Cannot write changes to '%1'. Nie mogę zapisać zmian do '%1'. - + Add Ignore Pattern Dodaj ignorowany - + Add a new ignore pattern: Dodaj nowy ignorowany: diff --git a/translations/client_pt.ts b/translations/client_pt.ts index f3eb3ec897..5bdf1dd69a 100644 --- a/translations/client_pt.ts +++ b/translations/client_pt.ts @@ -812,112 +812,112 @@ Continuando a sincronização fará com que todos os seus ficheiros sejam substi OCC::FolderMan - + Could not reset folder state Não foi possível reiniciar o estado da pasta - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Foi encontrado um 'journal' de sincronização, mas não foi possível removê-lo. Por favor, certifique-se que nenhuma aplicação o está a utilizar. - + (backup) (cópia de segurança) - + (backup %1) (cópia de segurança %1) - + Undefined State. Estado indefinido. - + Waiting to start syncing. A aguardar para iniciar a sincronização. - + Preparing for sync. A preparar para sincronizar. - + Sync is running. A sincronização está em execução. - + Last Sync was successful. A última sincronização foi bem sucedida. - + Last Sync was successful, but with warnings on individual files. A última sincronização foi bem sucedida, mas com avisos nos ficheiros individuais. - + Setup Error. Erro de instalação. - + User Abort. Abortado pelo utilizador. - + Sync is paused. A sincronização está pausada. - + %1 (Sync is paused) %1 (A sincronização está pausada) - + No valid folder selected! Não foi selecionada nenhuma pasta válida! - + The selected path is not a folder! O caminho selecionado não é uma pasta! - + You have no permission to write to the selected folder! Não tem permissão para gravar para a pasta selecionada! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! A pasta local %1 contém hiperligação simbólica. O destino da hiperligação já contém uma pasta sincronizada. Por favor, escolha outra! - + There is already a sync from the server to this local folder. Please pick another local folder! Já existe uma sincronização do servidor para esta pasta local. Por favor escolha outra pasta local! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! A pasta local %1 já contém uma pasta utilizada numa ligação de sincronização de pasta. Por favor, escolha outra! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! A pasta local %1 já contém uma pasta usada numa ligação de sincronização de pasta. Por favor, escolha outra! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! A pasta local %1 é uma hiperligação simbólica. A hiperligação de destino já contém uma pasta usada numa ligação de sincronização de pasta. Por favor, escolha outra! @@ -1350,22 +1350,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Os itens onde é permitido a eliminação serão eliminados se estes impedirem a remoção de uma diretoria. Isto é útil para os metadados. - + Could not open file Não foi possível abrir o ficheiro - + Cannot write changes to '%1'. Não foi possível gravar as alterações para '%1' - + Add Ignore Pattern Adicione Padrão de ignorar - + Add a new ignore pattern: Adicione um novo padrão de ignorar: diff --git a/translations/client_pt_BR.ts b/translations/client_pt_BR.ts index 9c6c86815a..9bb8a78516 100644 --- a/translations/client_pt_BR.ts +++ b/translations/client_pt_BR.ts @@ -810,112 +810,112 @@ Continuar a sincronização como normal fará com que todos os seus arquivos sej OCC::FolderMan - + Could not reset folder state Não foi possível redefinir o estado da pasta - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Uma velha revista de sincronização '%1' foi encontrada, mas não pôde ser removida. Por favor, certifique-se de que nenhuma aplicação está a usá-la. - + (backup) (backup) - + (backup %1) (backup %1) - + Undefined State. Estado indefinido. - + Waiting to start syncing. À espera do início da sincronização. - + Preparing for sync. Preparando para sincronização. - + Sync is running. A sincronização está ocorrendo. - + Last Sync was successful. A última sincronização foi feita com sucesso. - + Last Sync was successful, but with warnings on individual files. A última sincronização foi executada com sucesso, mas com advertências em arquivos individuais. - + Setup Error. Erro de Configuração. - + User Abort. Usuário Abortou. - + Sync is paused. Sincronização pausada. - + %1 (Sync is paused) %1 (Pausa na Sincronização) - + No valid folder selected! Nenhuma pasta válida selecionada! - + The selected path is not a folder! O caminho selecionado não é uma pasta! - + You have no permission to write to the selected folder! Voce não tem permissão para escrita na pasta selecionada! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! A pasta local %1 contém um link simbólico. O destino do link contém uma pasta já sincronizados. Por favor, escolha uma outra! - + There is already a sync from the server to this local folder. Please pick another local folder! Já existe uma sincronização do servidor para esta pasta local. Por favor, escolha uma outra pasta local! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! A pasta local %1 já contém uma pasta utilizada numa ligação de sincronização de pasta. Por favor, escolha outra! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! A pasta local %1 já está contida em uma pasta usada em uma conexão de sincronização de pastas. Por favor, escolha outra! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! A pasta local %1 é um link simbólico. O destino do link já está contido em uma pasta usada em uma conexão de sincronização de pastas. Por favor, escolha outra! @@ -1091,7 +1091,7 @@ Continuar a sincronização como normal fará com que todos os seus arquivos sej Click to select a local folder to sync. - Click para selecionar uma pasta local para sincronização. + Clique para selecionar uma pasta local para sincronização. @@ -1294,7 +1294,7 @@ Continuar a sincronização como normal fará com que todos os seus arquivos sej <a href="%1">Click here</a> to request an app password from the web interface. - <a href="%1">Click aqui</a> para solicitar uma senha de aplicativo na interface da web. + <a href="%1">Clique aqui</a> para solicitar uma senha de aplicativo na interface da web. @@ -1349,22 +1349,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Itens onde a eliminação é permitida serão excluídos se eles evitarem que um diretório seja removido. Isso é útil para metadados. - + Could not open file Não foi possível abrir o arquivo - + Cannot write changes to '%1'. Não é possível gravar as alterações em '%1'. - + Add Ignore Pattern Adicionar Ignorar Padrão - + Add a new ignore pattern: Adicionar um novo padrão ignorar: @@ -1468,7 +1468,7 @@ Itens onde a eliminação é permitida serão excluídos se eles evitarem que um Skip this time - Pular desta vêz + Pular desta vez diff --git a/translations/client_ru.ts b/translations/client_ru.ts index 2587ed5cd1..75d0152827 100644 --- a/translations/client_ru.ts +++ b/translations/client_ru.ts @@ -810,112 +810,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Невозможно сбросить состояние каталога - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Найден старый журнал синхронизации '%1', и он не может быть удалён. Убедитесь что он не открыт в другом приложении. - + (backup) (резервная копия) - + (backup %1) (резервная копия %1) - + Undefined State. Неопределенное состояние. - + Waiting to start syncing. Ожидание запуска синхронизации. - + Preparing for sync. Подготовка к синхронизации. - + Sync is running. Идет синхронизация. - + Last Sync was successful. Последняя синхронизация прошла успешно. - + Last Sync was successful, but with warnings on individual files. Последняя синхронизация прошла успешно, но были предупреждения для некоторых файлов. - + Setup Error. Ошибка установки. - + User Abort. Отмена пользователем. - + Sync is paused. Синхронизация приостановлена. - + %1 (Sync is paused) %! (синхронизация приостановлена) - + No valid folder selected! Не выбран валидный каталог! - + The selected path is not a folder! Выбранный путь не является каталогом! - + You have no permission to write to the selected folder! У вас недостаточно прав для записи в выбранный каталог! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Локальный каталог %1 содержит символьную ссылку. Место, на которое указывает ссылка, уже содержит засинхронизированный каталог. Пожалуйста, выберите другой! - + There is already a sync from the server to this local folder. Please pick another local folder! Уже есть синхронизация с сервера в этот локальный каталог. Пожалуйста, выберите другой локальный каталог! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Локальная директория %1 уже содержит папку, которая используется для синхронизации. Пожалуйста выберите другую! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Локальная директория %1 уже содержит директорию, которая используется для синхронизации. Пожалуйста выберите другую! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Локальная директория %1 является символьной ссылкой. Эта ссылка указывает на путь, находящийся внутри директории, уже используемой для синхронизации. Пожалуйста укажите другую! @@ -1347,22 +1347,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Элементы, где это разрешается, будут удалены, в случае если они помешают удалению папки. Используется для метаданных. - + Could not open file Невозможно открыть файл - + Cannot write changes to '%1'. Невозможно записать изменения в '%1'. - + Add Ignore Pattern Добавить шаблон игнорирования - + Add a new ignore pattern: Добавить новый шаблон игнорирования: diff --git a/translations/client_sk.ts b/translations/client_sk.ts index 94b0ec7e16..e27219054b 100644 --- a/translations/client_sk.ts +++ b/translations/client_sk.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Nemožno resetovať stav priečinka - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Starý synchronizačný žurnál '%1' nájdený, avšak neodstrániteľný. Prosím uistite sa, že žiadna aplikácia ho práve nevyužíva. - + (backup) (záloha) - + (backup %1) (záloha %1) - + Undefined State. Nedefinovaný stav. - + Waiting to start syncing. Čaká sa na začiatok synchronizácie - + Preparing for sync. Príprava na synchronizáciu. - + Sync is running. Synchronizácia prebieha. - + Last Sync was successful. Posledná synchronizácia sa úspešne skončila. - + Last Sync was successful, but with warnings on individual files. Posledná synchronizácia bola úspešná, ale s varovaniami pre individuálne súbory. - + Setup Error. Chyba pri inštalácii. - + User Abort. Zrušené používateľom. - + Sync is paused. Synchronizácia je pozastavená. - + %1 (Sync is paused) %1 (Synchronizácia je pozastavená) - + No valid folder selected! Nebol zvolený platný priečinok. - + The selected path is not a folder! Zvolená cesta nie je priečinok. - + You have no permission to write to the selected folder! Nemáte oprávnenia pre zápis do daného priečinka! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from - + Could not open file Nemožno otvoriť súbor - + Cannot write changes to '%1'. Nemožno zapísať zmeny do '%1'. - + Add Ignore Pattern Pridať vzor ignorovaného súboru - + Add a new ignore pattern: Pridať nový vzor ignorovaného súboru: diff --git a/translations/client_sl.ts b/translations/client_sl.ts index 57fced1f7a..eaec8fcec7 100644 --- a/translations/client_sl.ts +++ b/translations/client_sl.ts @@ -812,112 +812,112 @@ Z nadaljevanjem usklajevanja bodo vse trenutne datoteke prepisane s starejšimi OCC::FolderMan - + Could not reset folder state Ni mogoče ponastaviti stanja mape - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Obstaja starejši dnevnik usklajevanja '%1', vendar ga ni mogoče odstraniti. Preverite, ali je datoteka v uporabi. - + (backup) (varnostna kopija) - + (backup %1) (varnostna kopija %1) - + Undefined State. Nedoločeno stanje. - + Waiting to start syncing. Čakanje začetek usklajevanja - + Preparing for sync. Poteka priprava za usklajevanje. - + Sync is running. Usklajevanje je v teku. - + Last Sync was successful. Zadnje usklajevanje je bilo uspešno končano. - + Last Sync was successful, but with warnings on individual files. Zadnje usklajevanje je bilo sicer uspešno, vendar z opozorili za posamezne datoteke. - + Setup Error. Napaka nastavitve. - + User Abort. Uporabniška prekinitev. - + Sync is paused. Usklajevanje je začasno v premoru. - + %1 (Sync is paused) %1 (usklajevanje je v premoru) - + No valid folder selected! Ni izbrane veljavne mape! - + The selected path is not a folder! Izbrana pot ni mapa! - + You have no permission to write to the selected folder! Ni ustreznih dovoljenj za pisanje v izbrano mapo! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! Krajevna mapa %1 vsebuje simbolno povezavo. Ciljno mesto povezave že vključuje mapo, ki se usklajuje. Izbrati je treba drugo. - + There is already a sync from the server to this local folder. Please pick another local folder! Za to krajevno pot je že ustvarjeno mesto za usklajevanje. Izbrati je treba drugo. - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Krajevna mapa %1 že vključuje mapo, ki je določena za usklajevanje. Izbrati je treba drugo. - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Krajevna mapa %1 je že v določena za usklajevanje. Izbrati je treba drugo. - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Krajevna mapa %1 je simbolna povezava. Cilj povezave že vsebuje mapo, ki je uporabljena pri povezavi usklajevanja mape. Izberite drugo. @@ -1350,22 +1350,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Predmeti na mestu, kjer je brisanje dovoljeno, bodo izbisani, v kolikor zaradi njih brisanje mape ni mogoče. Možnost je uporabna pri metapodatkih. - + Could not open file Datoteke ni mogoče odpreti - + Cannot write changes to '%1'. Ni mogoče zapisati sprememb v '%1'. - + Add Ignore Pattern Dodaj vzorec za izpuščanje - + Add a new ignore pattern: Dodaj nov vzorec za izpuščanje: diff --git a/translations/client_sr.ts b/translations/client_sr.ts index 8a6b33955a..6ab459366c 100644 --- a/translations/client_sr.ts +++ b/translations/client_sr.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Не могу да ресетујем стање фасцикле - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Пронађен је стари журнал синхронизације „%1“ али се не може уклонити. Проверите да га нека апликација тренутно не користи. - + (backup) (резерва) - + (backup %1) (резерва %1) - + Undefined State. Неодређено стање. - + Waiting to start syncing. - + Preparing for sync. Припремам синхронизацију. - + Sync is running. Синхронизација у току. - + Last Sync was successful. Последња синхронизација је била успешна. - + Last Sync was successful, but with warnings on individual files. Последња синхронизација је била успешна али са упозорењима за поједине фајлове. - + Setup Error. Грешка подешавања. - + User Abort. Корисник прекинуо. - + Sync is paused. Синхронизација је паузирана. - + %1 (Sync is paused) %1 (синхронизација паузирана) - + No valid folder selected! - + The selected path is not a folder! - + You have no permission to write to the selected folder! Немате дозволе за упис у изабрану фасциклу! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from - + Could not open file Не могу да отворим фајл - + Cannot write changes to '%1'. Не могу да упишем измене у „%1“ - + Add Ignore Pattern Додавање шаблона за игнорисање - + Add a new ignore pattern: Додајте нови шаблон за игнорисање: diff --git a/translations/client_sv.ts b/translations/client_sv.ts index d66808970a..804934345f 100644 --- a/translations/client_sv.ts +++ b/translations/client_sv.ts @@ -805,112 +805,112 @@ Om du fortsätter synkningen kommer alla dina filer återställas med en äldre OCC::FolderMan - + Could not reset folder state Kunde inte återställa mappens skick - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. En gammal synkroniseringsjournal '%1' hittades, men kunde inte raderas. Vänligen se till att inga program för tillfället använder den. - + (backup) (säkerhetskopia) - + (backup %1) (säkerhetkopia %1) - + Undefined State. Okänt tillstånd. - + Waiting to start syncing. Väntar på att starta synkronisering. - + Preparing for sync. Förbereder synkronisering - + Sync is running. Synkronisering pågår. - + Last Sync was successful. Senaste synkronisering lyckades. - + Last Sync was successful, but with warnings on individual files. Senaste synkning lyckades, men det finns varningar för vissa filer! - + Setup Error. Inställningsfel. - + User Abort. Användare Avbryt - + Sync is paused. Synkronisering är pausad. - + %1 (Sync is paused) %1 (Synk är stoppad) - + No valid folder selected! Ingen giltig mapp markerad! - + The selected path is not a folder! Den markerade sökvägen är inte en mapp! - + You have no permission to write to the selected folder! Du har inga skrivrättigheter till den valda mappen! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! Den lokala mappen %1 innehåller redan en mapp som synkas. Var god välj en annan! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! Den lokala mappen %1 finns redan inuti en mapp som synkas. Var god välj en annan! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! Den lokala mappen %1 är en symbolisk länk. Länkmålet finns redan inuti en mapp som synkas. Var god välj en annan! @@ -1343,22 +1343,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Objekt som tillåter radering kommer tas bort om de förhindrar en mapp att tas bort. Det är användbart för meta-data. - + Could not open file Kunde inte öppna fil - + Cannot write changes to '%1'. Kan inte skriva förändringar till '%1'. - + Add Ignore Pattern Lägg till synk-filter - + Add a new ignore pattern: Lägg till ett nytt synk-filter: diff --git a/translations/client_th.ts b/translations/client_th.ts index fa56f79241..376816964a 100644 --- a/translations/client_th.ts +++ b/translations/client_th.ts @@ -813,112 +813,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state ไม่สามารถรีเซ็ตสถานะโฟลเดอร์ - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. บนบันทึกการประสานข้อมูลเก่า '%1' แต่ไม่สามารถลบออกได้ กรุณาตรวจสอบให้แน่ใจว่าไม่มีแอพฯ หรือการทำงานใดๆที่ใช้มันอยู่ - + (backup) (สำรองข้อมูล) - + (backup %1) (สำรองข้อมูล %1) - + Undefined State. สถานะที่ยังไม่ได้ถูกกำหนด - + Waiting to start syncing. กำลังรอเริ่มต้นการประสานข้อมูล - + Preparing for sync. กำลังเตรียมการประสานข้อมูล - + Sync is running. การประสานข้อมูลกำลังทำงาน - + Last Sync was successful. ประสานข้อมูลครั้งล่าสุดเสร็จเรียบร้อยแล้ว - + Last Sync was successful, but with warnings on individual files. การประสานข้อมูลสำเร็จ แต่มีคำเตือนในแต่ละไฟล์ - + Setup Error. เกิดข้อผิดพลาดในการติดตั้ง - + User Abort. ยกเลิกผู้ใช้ - + Sync is paused. การประสานข้อมูลถูกหยุดไว้ชั่วคราว - + %1 (Sync is paused) %1 (การประสานข้อมูลถูกหยุดชั่วคราว) - + No valid folder selected! เลือกโฟลเดอร์ไม่ถูกต้อง! - + The selected path is not a folder! เส้นทางที่เลือกไม่ใช่โฟลเดอร์! - + You have no permission to write to the selected folder! คุณมีสิทธิ์ที่จะเขียนโฟลเดอร์ที่เลือกนี้! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! โฟลเดอร์ต้นทาง %1 ได้ถูกเก็บข้อมูลของพาทแล้ว ลิงค์เป้าหมายมีโฟลเดอร์ที่ประสานข้อมูลแล้ว โปรดเลือกอันอื่น! - + There is already a sync from the server to this local folder. Please pick another local folder! โฟลเดอร์ต้นทางนี้ได้ถูกประสานข้อมูลกับเซิร์ฟเวอร์แล้ว โปรดเลือกโฟลเดอร์ต้นทางอื่นๆ! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! เนื้อหาโฟลเดอร์ต้นทาง %1 ได้ถูกใช้ไปแล้วในโฟลเดอร์ที่ประสานข้อมูล กรุณาเลือกอีกอันหนึ่ง! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! เนื้อหาของโฟลเดอร์ต้นทาง %1 ไดถูกใช้ไปแล้วในโฟลเดอร์ที่ประสานข้อมูล กรุณาเลือกอีกอันหนึ่ง! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! โฟลเดอร์ต้นทาง %1 เป็นการเชื่อมโยงสัญลักษณ์ เป้าหมายของลิงค์มีเนื้อหาที่ถูกใช้ไปแล้วในโฟลเดอร์ที่ประสานข้อมูล กรุณาเลือกอีกอันหนึ่ง! @@ -1352,22 +1352,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from รายการที่ลบจะถูกอนุญาตให้ลบถ้าพวกเขาป้องกันไม่ให้ไดเรกทอรีถูกลบออก นี้จะเป็นประโยชน์สำหรับข้อมูล meta - + Could not open file ไม่สามารถเปิดไฟล์ - + Cannot write changes to '%1'. ไม่สามารถเขียนเปลี่ยนเป็น '%1' - + Add Ignore Pattern เพิ่มการละเว้นรูปแบบ - + Add a new ignore pattern: เพิ่มการละเว้นรูปแบบใหม่: diff --git a/translations/client_tr.ts b/translations/client_tr.ts index 942f49a531..99944a8804 100644 --- a/translations/client_tr.ts +++ b/translations/client_tr.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Klasör durumu sıfırılanamadı - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Eski eşitleme günlüğü '%1' bulundu ancak kaldırılamadı. Başka bir uygulama tarafından kullanılmadığından emin olun. - + (backup) (yedek) - + (backup %1) (yedek %1) - + Undefined State. Tanımlanmamış Durum. - + Waiting to start syncing. Eşitlemenin başlanması bekleniyor. - + Preparing for sync. Eşitleme için hazırlanıyor. - + Sync is running. Eşitleme çalışıyor. - + Last Sync was successful. Son Eşitleme başarılı oldu. - + Last Sync was successful, but with warnings on individual files. Son eşitleme başarılıydı, ancak tekil dosyalarda uyarılar vardı. - + Setup Error. Kurulum Hatası. - + User Abort. Kullanıcı İptal Etti. - + Sync is paused. Eşitleme duraklatıldı. - + %1 (Sync is paused) %1 (Eşitleme duraklatıldı) - + No valid folder selected! Geçerli klasör seçilmedi! - + The selected path is not a folder! Seçilen yol bir klasör değil! - + You have no permission to write to the selected folder! Seçilen klasöre yazma izniniz yok! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! %1 yerel klasörü zaten bir eşitleme klasörü içermektedir. Lütfen farklı bir seçim yapın! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! %1 yerel klasörü zaten bir eşitleme klasörü içindedir. Lütfen farklı bir seçim yapın! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! %1 yerel klasörü sembolik bağlantıdır. Bu bağlantının işaretlediği klasör zaten yapılandırılmış bir klasör içindedir. Lütfen farklı bir seçim yapın! @@ -1341,22 +1341,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from Bir dizinin silinmesine engel oluyorsa silmeye izin verilen yerlerdeki ögeler silinecektir. Bu ham veriler için kullanışlıdır. - + Could not open file Dosya açılamadı - + Cannot write changes to '%1'. Değişiklikler '%1' üzerine yazılamıyor. - + Add Ignore Pattern Yoksayma Deseni Ekle - + Add a new ignore pattern: Yeni bir yoksayma deseni ekle: diff --git a/translations/client_uk.ts b/translations/client_uk.ts index f817777544..5f4a399af1 100644 --- a/translations/client_uk.ts +++ b/translations/client_uk.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state Не вдалося скинути стан теки - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. Знайдено старий журнал синхронізації '%1', його неможливо видалити. Будь ласка, впевніться що він не відкритий в іншій програмі. - + (backup) (Резервна копія) - + (backup %1) (Резервна копія %1) - + Undefined State. Невизначений стан. - + Waiting to start syncing. Очікування початку синхронізації. - + Preparing for sync. Підготовка до синхронізації - + Sync is running. Синхронізація запущена. - + Last Sync was successful. Остання синхронізація була успішною. - + Last Sync was successful, but with warnings on individual files. Остання синхронізація пройшла вдало, але були зауваження про деякі файли. - + Setup Error. Помилка встановлення. - + User Abort. Скасовано користувачем. - + Sync is paused. Синхронізація призупинена. - + %1 (Sync is paused) %1 (Синхронізація призупинена) - + No valid folder selected! - + The selected path is not a folder! - + You have no permission to write to the selected folder! У вас немає прав на запис в цю теку! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! @@ -1339,22 +1339,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from - + Could not open file Не вдалося відкрити файл - + Cannot write changes to '%1'. Неможливо запиасати зміни до '%1'. - + Add Ignore Pattern Додати шаблон ігнорування - + Add a new ignore pattern: Додати новий шаблон ігнорування: diff --git a/translations/client_zh_CN.ts b/translations/client_zh_CN.ts index 356ced7f28..57fbe2b663 100644 --- a/translations/client_zh_CN.ts +++ b/translations/client_zh_CN.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state 不能重置文件夹状态 - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. 一个旧的同步日志 '%1' 被找到,但是不能被移除。请确定没有应用程序正在使用它。 - + (backup) (备份) - + (backup %1) (备份 %1) - + Undefined State. 未知状态。 - + Waiting to start syncing. 等待启动同步。 - + Preparing for sync. 准备同步。 - + Sync is running. 同步正在运行。 - + Last Sync was successful. 最后一次同步成功。 - + Last Sync was successful, but with warnings on individual files. 上次同步已成功,不过一些文件出现了警告。 - + Setup Error. 安装失败 - + User Abort. 用户撤销。 - + Sync is paused. 同步已暂停。 - + %1 (Sync is paused) %1 (同步已暂停) - + No valid folder selected! 没有选择有效的文件夹! - + The selected path is not a folder! 选择的路径不是一个文件夹! - + You have no permission to write to the selected folder! 你没有写入所选文件夹的权限! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! 本地文件夹 %1 包含有正在使用的同步文件夹,请选择另一个! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! 本地文件夹 %1 是正在使用的同步文件夹,请选择另一个! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! 选择的文件夹 %1 是一个符号连接,连接指向的是正在使用的同步文件夹,请选择另一个! @@ -1341,22 +1341,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from 如果选中的项目正在阻止文件夹的删除,它们也会被删除。这对于元数据很有用。 - + Could not open file 不能打开文件 - + Cannot write changes to '%1'. 无法向 %1 中写入修改。 - + Add Ignore Pattern 增加忽略模式 - + Add a new ignore pattern: 增加新的忽略模式: diff --git a/translations/client_zh_TW.ts b/translations/client_zh_TW.ts index 5c67ec5320..460511e108 100644 --- a/translations/client_zh_TW.ts +++ b/translations/client_zh_TW.ts @@ -803,112 +803,112 @@ Continuing the sync as normal will cause all your files to be overwritten by an OCC::FolderMan - + Could not reset folder state 無法重置資料夾狀態 - + An old sync journal '%1' was found, but could not be removed. Please make sure that no application is currently using it. 發現較舊的同步處理日誌'%1',但無法移除。請確認沒有應用程式正在使用它。 - + (backup) (備份) - + (backup %1) (備份 %1) - + Undefined State. 未知狀態 - + Waiting to start syncing. 正在等待同步開始 - + Preparing for sync. 正在準備同步。 - + Sync is running. 同步執行中 - + Last Sync was successful. 最後一次同步成功 - + Last Sync was successful, but with warnings on individual files. 最新一次的同步已經成功,但是有部份檔案有問題 - + Setup Error. 安裝失敗 - + User Abort. 使用者中斷。 - + Sync is paused. 同步已暫停 - + %1 (Sync is paused) %1 (同步暫停) - + No valid folder selected! 沒有選擇有效的資料夾 - + The selected path is not a folder! 所選的路徑並非資料夾! - + You have no permission to write to the selected folder! 您沒有權限來寫入被選取的資料夾! - + The local folder %1 contains a symbolic link. The link target contains an already synced folder Please pick another one! - + There is already a sync from the server to this local folder. Please pick another local folder! - + The local folder %1 already contains a folder used in a folder sync connection. Please pick another one! 本地資料夾 %1 裡已經有被資料夾同步功能使用的資料夾,請選擇其他資料夾! - + The local folder %1 is already contained in a folder used in a folder sync connection. Please pick another one! 本地資料夾 %1 是被包含在一個已經被資料夾同步功能使用的資料夾,請選擇其他資料夾! - + The local folder %1 is a symbolic link. The link target is already contained in a folder used in a folder sync connection. Please pick another one! 本地資料夾 %1 是一個捷徑,此捷徑的目標是被包含在一個已經被資料夾同步功能使用的資料夾,請選擇其他資料夾! @@ -1341,22 +1341,22 @@ Items where deletion is allowed will be deleted if they prevent a directory from 當資料夾被移除時,會根據清單裡的允許刪除選項來避免那些檔案會被移除。而這對元資料是有用的。 - + Could not open file 無法開啟檔案 - + Cannot write changes to '%1'. %1 無法寫入變更。 - + Add Ignore Pattern 增加忽略格式 - + Add a new ignore pattern: 增加一個新的忽略格式: From f44d3914ef0e69dc3c70d03f85656058ab1484bc Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 10:01:32 +0200 Subject: [PATCH 54/64] owncloudcmd: Explain --debug parameter --- src/cmd/cmd.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/cmd.cpp b/src/cmd/cmd.cpp index 0535875cd4..762c27eb68 100644 --- a/src/cmd/cmd.cpp +++ b/src/cmd/cmd.cpp @@ -188,6 +188,7 @@ void help() std::cout << " --downlimit [n] Limit the download speed of files to n KB/s" << std::endl; std::cout << " -h Sync hidden files,do not ignore them" << std::endl; std::cout << " --version, -v Display version and exit" << std::endl; + std::cout << " --debug More verbose logging" << std::endl; std::cout << "" << std::endl; exit(0); } From 1332e7d66a4e317b2096684bcf719e1b8186a64a Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 11:59:24 +0200 Subject: [PATCH 55/64] Jenkinsfile: 2.3.3 will ship with Qt 5. This should fix the current CI run too --- Jenkinsfile | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 090831de44..01101cc3a8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,22 +5,6 @@ node('CLIENT') { checkout scm sh '''git submodule update --init''' - stage 'Qt4' - sh '''rm -rf build - mkdir build - cd build - cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON .. - make -j4 - ctest --output-on-failure''' - - stage 'Qt4 - clang' - sh '''rm -rf build - mkdir build - cd build - cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON .. - make -j4 - ctest --output-on-failure''' - stage 'Qt5' sh '''rm -rf build mkdir build From cd5ad7db6469225105ad53eda25110ebf6b3b754 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 12:12:08 +0200 Subject: [PATCH 56/64] Jenkinsfile: Run full testing --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 01101cc3a8..993a7f26bb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' @@ -17,7 +17,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' From 30bcd45a148392bf3ad5f7e5892965b2a01432aa Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 12:12:08 +0200 Subject: [PATCH 57/64] Jenkinsfile: Run full testing --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 01101cc3a8..993a7f26bb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' @@ -17,7 +17,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' From bfe095b0651a2833978b93dd3b06b080c5ea3d8b Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 12:18:21 +0200 Subject: [PATCH 58/64] Jenkinsfile: Run verbose tests --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 993a7f26bb..0833a5e6f1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,7 +11,7 @@ node('CLIENT') { cd build cmake -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 - ctest --output-on-failure''' + ctest -V --output-on-failure''' stage 'Qt5 - clang' sh '''rm -rf build @@ -19,7 +19,7 @@ node('CLIENT') { cd build cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 - ctest --output-on-failure''' + ctest -V --output-on-failure''' stage 'Win32' From bc946053a39a33ebdfa79de5738d3feb61bfd778 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 15:02:26 +0200 Subject: [PATCH 59/64] Jenkinsfile: Compile in debug because of all the asserts --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 993a7f26bb..d85402c40d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' @@ -17,7 +17,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest --output-on-failure''' From cb7d74a063ad7afeff1b7c7333b068996f50d9ef Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 21 Jun 2017 15:02:26 +0200 Subject: [PATCH 60/64] Jenkinsfile: Compile in debug because of all the asserts --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0833a5e6f1..fc0acb898b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest -V --output-on-failure''' @@ -17,7 +17,7 @@ node('CLIENT') { sh '''rm -rf build mkdir build cd build - cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. + cmake -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF .. make -j4 ctest -V --output-on-failure''' From 6a298d180dfc96c3407cd9051f3afb2e9d70d6bf Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Thu, 22 Jun 2017 02:22:09 +0200 Subject: [PATCH 61/64] [tx-robot] updated from transifex --- mirall.desktop.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirall.desktop.in b/mirall.desktop.in index 7dc441ec21..b3a21737b9 100644 --- a/mirall.desktop.in +++ b/mirall.desktop.in @@ -45,6 +45,9 @@ X-GNOME-Autostart-Delay=3 # Translations +# Translations + + # Translations Comment[oc]=@APPLICATION_NAME@ sincronizacion del client GenericName[oc]=Dorsièr de Sincronizacion From 2244b35a6daff226f4da3c251f99550dac0d0197 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 22 Jun 2017 15:09:28 +0200 Subject: [PATCH 62/64] test_journal.db: Add checksumtype table --- test/test_journal.db | Bin 57344 -> 57344 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/test_journal.db b/test/test_journal.db index 2b58c07cb86532477aeeaaa7fc5575e173e563b9..7a95c4455556c729147d105f755be18482f42cda 100644 GIT binary patch delta 290 zcmZoTz}#?vd4jayF$M+(3m}#SVg(=;oTy{WdW=E$8P~>?x$1&UnhdOr2@FiSObN{A z850;kY;5#ntZ(GyW*1jgWo(QsNleN~P0mP7&Mq#^EvYO(VGB72xjKfpDug&X`M4?| ztJ2`gOi}Rk3vqRK4N?dQ^7M5Kid67+jnq*<0$h2Cxv2^vt`Q*$p?;o$p{_7FVHg8S zb7`9MOqNrVkw>;7-Vm853iKMwW?ikzl8n5Y86}umHnVvAVQ1vp%qa4od9gr%$fgW- S4o3OO90mD|Vw)=pI`RQZMNZfN delta 94 zcmZoTz}#?vd4jayQ3eJE3m}#SVkICJn5bjSdXz!;8Pmp;x$3+?5oRV`1}0sm1m^P_ u8|9fc>uOz=Tr3#CvdDvDvtYn`@re@zH)XJMFe*;wD9C3N-CR-7kq-bOFc{SU From 1e98ba27c65defc9d626c1249381ccb92122e43e Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 22 Jun 2017 15:11:27 +0200 Subject: [PATCH 63/64] CSyncSqliteTest: Fix test --- CMakeLists.txt | 2 -- test/CMakeLists.txt | 1 + test/testcsyncsqlite.cpp | 7 ++++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f02c9e9a5..116dca4cc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -182,8 +182,6 @@ endif() configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) -configure_file(test/test_journal.db "${CMAKE_BINARY_DIR}/test/test_journal.db" COPYONLY) - include(OwnCloudCPack.cmake) add_definitions(-DUNICODE) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c9726d584b..ac0f1dca1e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,3 +59,4 @@ list(APPEND FolderMan_SRC ${FolderWatcher_SRC}) list(APPEND FolderMan_SRC stub.cpp ) owncloud_add_test(FolderMan "${FolderMan_SRC}") +configure_file(test_journal.db "${PROJECT_BINARY_DIR}/bin/test_journal.db" COPYONLY) diff --git a/test/testcsyncsqlite.cpp b/test/testcsyncsqlite.cpp index 9d526afeef..09dc1528a4 100644 --- a/test/testcsyncsqlite.cpp +++ b/test/testcsyncsqlite.cpp @@ -21,10 +21,11 @@ private slots: memset(&_ctx, 0, sizeof(CSYNC)); - _ctx.statedb.file = c_strdup("./test_journal.db"); + QString db = QCoreApplication::applicationDirPath() + "/test_journal.db"; + _ctx.statedb.file = c_strdup(db.toLocal8Bit()); rc = csync_statedb_load((CSYNC*)(&_ctx), _ctx.statedb.file, &(_ctx.statedb.db)); - Q_ASSERT(rc == 0); + QVERIFY(rc == 0); } void testFullResult() { @@ -85,5 +86,5 @@ private slots: }; -QTEST_APPLESS_MAIN(TestCSyncSqlite) +QTEST_GUILESS_MAIN(TestCSyncSqlite) #include "testcsyncsqlite.moc" From 59bbbd5e66e41415e79a31079d130bbc5ae296b3 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 22 Jun 2017 15:42:56 +0200 Subject: [PATCH 64/64] Jenkinsfile: Some comments --- Jenkinsfile | 9 +++++++++ test/syncenginetestutils.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index fc0acb898b..f8d6f9dd72 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,12 @@ #!groovy +// +// We now run the tests in Debug mode so that ASSERTs are triggered. +// Ideally we should run the tests in both Debug and Release so we catch +// all possible error combinations. +// See also the top comment in syncenginetestutils.h +// + node('CLIENT') { stage 'Checkout' checkout scm @@ -37,6 +44,8 @@ node('CLIENT') { ctest . ''' } + + // Stage 'macOS' TODO } diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index ee15d8e33b..997e5054e5 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -17,6 +17,12 @@ #include #include +/* + * TODO: In theory we should use QVERIFY instead of Q_ASSERT for testing, but this + * only works when directly called from a QTest :-( + */ + + static const QUrl sRootUrl("owncloud://somehost/owncloud/remote.php/webdav/"); static const QUrl sRootUrl2("owncloud://somehost/owncloud/remote.php/dav/files/admin/"); static const QUrl sUploadUrl("owncloud://somehost/owncloud/remote.php/dav/uploads/admin/");