mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-07 18:46:49 +02:00
Compare commits
309 Commits
v1.3.0
...
v1.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24251bc223 | ||
|
|
f78749d2cd | ||
|
|
0995377d39 | ||
|
|
b9228e64ff | ||
|
|
c4084de716 | ||
|
|
3c667918e7 | ||
|
|
e55745cbcf | ||
|
|
e01ce20431 | ||
|
|
dce8cb83d9 | ||
|
|
8dc956c55b | ||
|
|
6c77921a32 | ||
|
|
55e4748f06 | ||
|
|
5ff9e02517 | ||
|
|
7f7ebc36f5 | ||
|
|
0e5bfc03ce | ||
|
|
b309d333a6 | ||
|
|
ee439382ed | ||
|
|
192212c682 | ||
|
|
148bdfdcd6 | ||
|
|
066c0ba189 | ||
|
|
9651f1cddf | ||
|
|
5feb9b0806 | ||
|
|
44b9ee19e7 | ||
|
|
cc16d19bc4 | ||
|
|
b96c2de2b7 | ||
|
|
f882b80708 | ||
|
|
4d7c014b23 | ||
|
|
1f274699e5 | ||
|
|
697e355f07 | ||
|
|
e89bdfc422 | ||
|
|
c2cc9e62a7 | ||
|
|
1f2ae0d061 | ||
|
|
91a39588c6 | ||
|
|
a642f86d5b | ||
|
|
00cf290574 | ||
|
|
b59952b539 | ||
|
|
88b4ff9809 | ||
|
|
ddd0965a82 | ||
|
|
0a9491ff46 | ||
|
|
32b44e3d87 | ||
|
|
268004b4ff | ||
|
|
6c0f6ae62e | ||
|
|
094f2bb540 | ||
|
|
f4da7f1fb0 | ||
|
|
b058185d3b | ||
|
|
eecb981736 | ||
|
|
46b870e260 | ||
|
|
1ffab7337d | ||
|
|
82fb8c49cf | ||
|
|
ff2d59d32f | ||
|
|
0ced165b3e | ||
|
|
d3378c131a | ||
|
|
0300a85295 | ||
|
|
60a116f3e0 | ||
|
|
ff4d2d488f | ||
|
|
b0852b4cf5 | ||
|
|
c047b4d4de | ||
|
|
6655da9d24 | ||
|
|
cc6abfc366 | ||
|
|
4e3d4c3153 | ||
|
|
c323041040 | ||
|
|
95d600c5f1 | ||
|
|
52a47fbc67 | ||
|
|
4e7c069c1f | ||
|
|
f89ffa513a | ||
|
|
0086916b4d | ||
|
|
df5ef6fe67 | ||
|
|
c9e51dcfc1 | ||
|
|
c05adfd817 | ||
|
|
055410e38f | ||
|
|
6163de378e | ||
|
|
22938cd697 | ||
|
|
a493f81ec2 | ||
|
|
87cb2a7114 | ||
|
|
a875b46a80 | ||
|
|
704ba791fd | ||
|
|
c24d6bd71c | ||
|
|
9b319cf189 | ||
|
|
1a9eb19f0d | ||
|
|
1943cc60b6 | ||
|
|
761c05c358 | ||
|
|
b08c1ada02 | ||
|
|
dab17e381c | ||
|
|
114f66f297 | ||
|
|
f8878833de | ||
|
|
364d4340fd | ||
|
|
6226a6ee8f | ||
|
|
c49edeb09d | ||
|
|
7e794cd94f | ||
|
|
933a62de01 | ||
|
|
23f8e3b4f8 | ||
|
|
3502edf71b | ||
|
|
4d8a371e43 | ||
|
|
01fd3242c4 | ||
|
|
9c289334e9 | ||
|
|
002142539b | ||
|
|
e1d1c10fad | ||
|
|
577bc546d8 | ||
|
|
85a832fb7c | ||
|
|
a9f23a8331 | ||
|
|
5d24599546 | ||
|
|
07d9d3770b | ||
|
|
c9ddb12b5a | ||
|
|
0932ee6051 | ||
|
|
ee1b8465a3 | ||
|
|
26bd164168 | ||
|
|
00e819bd92 | ||
|
|
740d33b378 | ||
|
|
f0b284eda7 | ||
|
|
da370c8b36 | ||
|
|
203b9c7f6b | ||
|
|
7932ec3cc1 | ||
|
|
3f15e02881 | ||
|
|
6fb5c04bde | ||
|
|
578bcc3522 | ||
|
|
99dea76fd1 | ||
|
|
b680540adf | ||
|
|
67f57a443c | ||
|
|
2b3b4f9daf | ||
|
|
ba01a697e6 | ||
|
|
16d81db117 | ||
|
|
4ce92f1a98 | ||
|
|
21c63637bd | ||
|
|
18f764e4d5 | ||
|
|
5930ca8ac7 | ||
|
|
49be4a3be2 | ||
|
|
1e50620f53 | ||
|
|
5e82dc1841 | ||
|
|
33d76962a7 | ||
|
|
6ce1c17ee1 | ||
|
|
8d9b4d3669 | ||
|
|
fb79b8a7f8 | ||
|
|
b0236eaa24 | ||
|
|
19bbff708e | ||
|
|
1399ea13cc | ||
|
|
a25d9fd3b4 | ||
|
|
72d51e4667 | ||
|
|
f6e3838eb2 | ||
|
|
c1fdecae2d | ||
|
|
4104db65bb | ||
|
|
36cb827406 | ||
|
|
69a4558fe4 | ||
|
|
928eae419f | ||
|
|
50edac8ee8 | ||
|
|
945951cda5 | ||
|
|
fa95a638af | ||
|
|
3b6aeb1fc8 | ||
|
|
6543a01418 | ||
|
|
9724e52f1b | ||
|
|
9413a30a08 | ||
|
|
6a9a2559d2 | ||
|
|
78b6f4df01 | ||
|
|
b7e88aa2ef | ||
|
|
224fd21612 | ||
|
|
a6bf33c501 | ||
|
|
306a9421fb | ||
|
|
d5885daf0f | ||
|
|
52b3f7105d | ||
|
|
7f6dc291c0 | ||
|
|
eacb849353 | ||
|
|
367bc401ee | ||
|
|
92af3ea725 | ||
|
|
582ce4cfa0 | ||
|
|
43ae3dfce5 | ||
|
|
ce851a7a8b | ||
|
|
b5b7589b41 | ||
|
|
b638341c14 | ||
|
|
7274417f84 | ||
|
|
1967226c71 | ||
|
|
227ea8ed24 | ||
|
|
e705db8339 | ||
|
|
be65f78174 | ||
|
|
fd6a17f3e6 | ||
|
|
0353d7b6a6 | ||
|
|
a64724be0e | ||
|
|
a0d9d41455 | ||
|
|
84e8ab5b71 | ||
|
|
f5bbb12434 | ||
|
|
a07d2cddd2 | ||
|
|
f1878640c8 | ||
|
|
edf8147561 | ||
|
|
3a9ab3a86f | ||
|
|
8f912ca0c5 | ||
|
|
a827056d28 | ||
|
|
6c90989584 | ||
|
|
08acf5e9aa | ||
|
|
bca295183b | ||
|
|
a400a2e0bb | ||
|
|
8c15839753 | ||
|
|
810024f4c9 | ||
|
|
de7bcca5fe | ||
|
|
6552a48639 | ||
|
|
aee0f0c882 | ||
|
|
e353193fbb | ||
|
|
fb547e9100 | ||
|
|
44289c8781 | ||
|
|
d4a5ab252d | ||
|
|
a3b3c28694 | ||
|
|
976c41a3b8 | ||
|
|
da087292fd | ||
|
|
274f59f93b | ||
|
|
85d810d2cf | ||
|
|
47f151c594 | ||
|
|
7b5ef2186e | ||
|
|
8236dafb96 | ||
|
|
56e5627b6b | ||
|
|
38db0eddab | ||
|
|
710625e2a3 | ||
|
|
a5e7af6c1f | ||
|
|
5fe4d2db2b | ||
|
|
b2c587e2f8 | ||
|
|
40c2d891c1 | ||
|
|
d5ad3a8a70 | ||
|
|
c74382af4f | ||
|
|
0be0111724 | ||
|
|
f0d454b511 | ||
|
|
b79a45403e | ||
|
|
1cc60e755b | ||
|
|
7fb7cc8c46 | ||
|
|
1400889b23 | ||
|
|
44fa9bd141 | ||
|
|
992dffa032 | ||
|
|
5fa7e48c24 | ||
|
|
3b00dfebed | ||
|
|
b42c7e07e6 | ||
|
|
ab7bfabf12 | ||
|
|
ab72644ace | ||
|
|
218fa040c8 | ||
|
|
b8f783f104 | ||
|
|
ae2e3e7fb1 | ||
|
|
edd9d9aee3 | ||
|
|
8c66085621 | ||
|
|
40ab325a37 | ||
|
|
7ae95b14f4 | ||
|
|
5da6103fb5 | ||
|
|
6b5b9db20a | ||
|
|
eb39d144e4 | ||
|
|
cfaaf4a2c4 | ||
|
|
279a738aa6 | ||
|
|
10b55f11a2 | ||
|
|
25065c4151 | ||
|
|
d2657bc154 | ||
|
|
4fde3f4a65 | ||
|
|
e398cfb27c | ||
|
|
3cc670ec29 | ||
|
|
c8d9e8458a | ||
|
|
892419e880 | ||
|
|
13fb49cf39 | ||
|
|
eabe3f968e | ||
|
|
2ca5eaaab9 | ||
|
|
eed3deac67 | ||
|
|
a63863b65c | ||
|
|
748ff13bce | ||
|
|
6c7700c2e7 | ||
|
|
c8ccb014c8 | ||
|
|
f1bd14e8de | ||
|
|
024d01a192 | ||
|
|
b2d02ef0bd | ||
|
|
751d7deda6 | ||
|
|
fff795146e | ||
|
|
c6219581f6 | ||
|
|
d0c5fb2395 | ||
|
|
6c2c81dc83 | ||
|
|
bfdb0c0012 | ||
|
|
d870d6c326 | ||
|
|
c06410e726 | ||
|
|
ef03ebe086 | ||
|
|
a217e8f24c | ||
|
|
c164beb040 | ||
|
|
5171e5880d | ||
|
|
2ef62524d6 | ||
|
|
4bbb29c2b4 | ||
|
|
261776cc78 | ||
|
|
3008142b1b | ||
|
|
152e729768 | ||
|
|
e7c77df59e | ||
|
|
4ff1a13f32 | ||
|
|
b9b18d6120 | ||
|
|
4945ce3c8c | ||
|
|
19aa8c63c0 | ||
|
|
efd11b61c6 | ||
|
|
1facb1f95d | ||
|
|
3db0788a91 | ||
|
|
e068098046 | ||
|
|
f2d289326b | ||
|
|
ae57f27eb9 | ||
|
|
a1767b2f7f | ||
|
|
5e9fcf7537 | ||
|
|
8192cc7eea | ||
|
|
2b8e1f2504 | ||
|
|
9d01f80744 | ||
|
|
1a04c9da67 | ||
|
|
d35e1baee1 | ||
|
|
2f16e50c87 | ||
|
|
3a662f7afb | ||
|
|
903a78623c | ||
|
|
9dd776ff6c | ||
|
|
5d9c664fba | ||
|
|
5c4b7d427d | ||
|
|
60a4180dd6 | ||
|
|
8e42721959 | ||
|
|
4553fa1d09 | ||
|
|
e43ff398cd | ||
|
|
c0cd255ea3 | ||
|
|
a0375fd000 | ||
|
|
6d847cd5f9 | ||
|
|
6470a3f539 | ||
|
|
c6111d09ce | ||
|
|
d6012854a9 |
@@ -4,6 +4,8 @@ project(mirall)
|
|||||||
set(PACKAGE "mirall")
|
set(PACKAGE "mirall")
|
||||||
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||||
|
|
||||||
|
include(Warnings)
|
||||||
|
|
||||||
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
||||||
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
||||||
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
||||||
@@ -62,9 +64,9 @@ endif()
|
|||||||
####
|
####
|
||||||
|
|
||||||
#### find libs
|
#### find libs
|
||||||
find_package(Qt4 4.6.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest REQUIRED )
|
find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED )
|
||||||
if( UNIX AND NOT APPLE ) # Fdo notifications
|
if( UNIX AND NOT APPLE ) # Fdo notifications
|
||||||
find_package(Qt4 4.6.0 COMPONENTS QtDBus REQUIRED )
|
find_package(Qt4 4.7.0 COMPONENTS QtDBus REQUIRED )
|
||||||
endif()
|
endif()
|
||||||
find_package(Csync REQUIRED)
|
find_package(Csync REQUIRED)
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
|||||||
28
ChangeLog
28
ChangeLog
@@ -1,5 +1,33 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
version 1.4.0beta1 (release 2013-08-08 ), csync 0.81.0 required
|
||||||
|
|
||||||
|
* New Scheduler: Only sync when there are actual changes in the server
|
||||||
|
* Add a Settings Dialog, move Proxy Settings there
|
||||||
|
* Transform folder Status Dialog into Account Settings, provide feedback via context menu
|
||||||
|
* Add Bandwidth Control
|
||||||
|
* Add a visual storage/quota indicator (context menu and account settings)
|
||||||
|
* Add progress indication (context menu and account settings)
|
||||||
|
* Introduce a sync history, persisting results across syncs
|
||||||
|
* Move ability to switch to mono icons from a switch to a Settings option
|
||||||
|
* Add "Launch on System Startup" GUI option
|
||||||
|
* Add "Show Desktop Nofications"GUI option (enabled by default)
|
||||||
|
top optionally disable sync notifications
|
||||||
|
* Add Help item, pointing to online reference
|
||||||
|
* Implement graphical selection of remote folders in FolderWizard
|
||||||
|
* Allow custom ignore patterns
|
||||||
|
* Add an editor for ingore patterns
|
||||||
|
* ALlow to flag certain ignore patterns as discardable
|
||||||
|
* Ensure to ship with all valid translations
|
||||||
|
* Add preliminary support for Shibboleth authentication
|
||||||
|
* Linux: Provide more icon sizes
|
||||||
|
* Linux: Do not trigger notifier on ignored files
|
||||||
|
* Windows: Reduce priority of CSync thread
|
||||||
|
* Documentation: Prem. updates to reflect UI changes
|
||||||
|
* Significant code refactorings
|
||||||
|
* Require Qt 4.7
|
||||||
|
* Known issue: Under certain conditions, a file will only get uploaded after up to five minutes
|
||||||
|
|
||||||
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
||||||
|
|
||||||
* Default proxy port to 8080
|
* Default proxy port to 8080
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( VERSION_MAJOR 1 )
|
set( VERSION_MAJOR 1 )
|
||||||
set( VERSION_MINOR 3 )
|
set( VERSION_MINOR 4 )
|
||||||
set( VERSION_PATCH 0 )
|
set( VERSION_PATCH 0 )
|
||||||
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX})
|
set( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta2")
|
||||||
set( SOVERSION 0 )
|
set( SOVERSION 0 )
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
!define OPTION_SECTION_SC_START_MENU
|
!define OPTION_SECTION_SC_START_MENU
|
||||||
!define OPTION_SECTION_SC_DESKTOP
|
!define OPTION_SECTION_SC_DESKTOP
|
||||||
!define OPTION_SECTION_SC_QUICK_LAUNCH
|
!define OPTION_SECTION_SC_QUICK_LAUNCH
|
||||||
!define OPTION_SECTION_SC_AUTOSTART
|
|
||||||
!define OPTION_FINISHPAGE
|
!define OPTION_FINISHPAGE
|
||||||
!define OPTION_FINISHPAGE_LAUNCHER
|
!define OPTION_FINISHPAGE_LAUNCHER
|
||||||
; !define OPTION_FINISHPAGE_RELEASE_NOTES
|
; !define OPTION_FINISHPAGE_RELEASE_NOTES
|
||||||
@@ -283,84 +282,20 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
!ifndef INSTALL_PATH
|
!ifndef INSTALL_PATH
|
||||||
;Main executable.
|
;Main executable.
|
||||||
File "${BUILD_PATH}\bin\${APPLICATION_EXECUTABLE}"
|
File "${BUILD_PATH}\bin\${APPLICATION_EXECUTABLE}"
|
||||||
File "${BUILD_PATH}\src\libowncloudsync.dll"
|
File "${BUILD_PATH}\src\lib${APPLICATION_SHORTNAME}sync.dll"
|
||||||
|
|
||||||
File "${BUILD_PATH}\src\mirall_ca.qm"
|
File "${BUILD_PATH}\src\mirall_*.qm"
|
||||||
File "${BUILD_PATH}\src\mirall_cs_CZ.qm"
|
; Make sure only to copy qt, not qt_help, etc
|
||||||
File "${BUILD_PATH}\src\mirall_da.qm"
|
File "${MING_SHARE}\qt4\translations\qt_??.qm"
|
||||||
File "${BUILD_PATH}\src\mirall_de.qm"
|
File "${MING_SHARE}\qt4\translations\qt_??_??.qm"
|
||||||
File "${BUILD_PATH}\src\mirall_el.qm"
|
File "${MING_SHARE}\qt4\translations\qtkeychain_*.qm"
|
||||||
File "${BUILD_PATH}\src\mirall_en.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_eo.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_es.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_es_AR.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_et_EE.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_eu.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_fa.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_fi_FI.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_fr.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_gl.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_he.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_hr.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_hu_HU.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_it.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ja_JP.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ko.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_lb.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_lt_LT.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_lv.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_mk.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ms_MY.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_nb_NO.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_nl.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_oc.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_pl.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_pt_BR.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_pt_PT.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ro.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ru.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ru_RU.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_si_LK.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_sk_SK.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_sl.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_sr@latin.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_sv.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_ta_LK.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_th_TH.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_tr.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_uk.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_vi.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_zh_CN.qm"
|
|
||||||
File "${BUILD_PATH}\src\mirall_zh_TW.qm"
|
|
||||||
|
|
||||||
#File "${MING_SHARE}\qt4\translations\qt_ar.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_cs.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_da.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_de.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_es.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_fa.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_fr.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_gl.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_he.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_hu.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_ja.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_ko.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_lt.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_pl.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_pt.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_ru.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_sk.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_sl.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_sv.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_uk.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_zh_CN.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
|
|
||||||
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
|
|
||||||
|
|
||||||
File "${MING_SHARE}\qt4\translations\qtkeychain_de.qm"
|
|
||||||
|
|
||||||
SetOutPath "$INSTDIR\accessible"
|
SetOutPath "$INSTDIR\accessible"
|
||||||
File "${ACCESSIBLE_DLL_PATH}\qtaccessiblewidgets4.dll"
|
File "${ACCESSIBLE_DLL_PATH}\qtaccessiblewidgets4.dll"
|
||||||
|
SetOutPath "$INSTDIR\imageformats"
|
||||||
|
File "${IMAGEFORMATS_DLL_PATH}\qgif4.dll"
|
||||||
|
File "${IMAGEFORMATS_DLL_PATH}\qjpeg4.dll"
|
||||||
|
File "${IMAGEFORMATS_DLL_PATH}\qico4.dll"
|
||||||
|
|
||||||
SetOutPath "$INSTDIR\modules"
|
SetOutPath "$INSTDIR\modules"
|
||||||
; FIXME: fix installation dir of module, currently needs manual copying to
|
; FIXME: fix installation dir of module, currently needs manual copying to
|
||||||
@@ -381,6 +316,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
File "${QT_DLL_PATH}\QtGui4.dll"
|
File "${QT_DLL_PATH}\QtGui4.dll"
|
||||||
File "${QT_DLL_PATH}\QtNetwork4.dll"
|
File "${QT_DLL_PATH}\QtNetwork4.dll"
|
||||||
File "${QT_DLL_PATH}\QtXml4.dll"
|
File "${QT_DLL_PATH}\QtXml4.dll"
|
||||||
|
File "${QT_DLL_PATH}\QtWebKit4.dll"
|
||||||
|
|
||||||
;QtKeyChain stuff
|
;QtKeyChain stuff
|
||||||
File "${MING_BIN}\libqtkeychain.dll"
|
File "${MING_BIN}\libqtkeychain.dll"
|
||||||
@@ -404,7 +340,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
|
|
||||||
; Other
|
; Other
|
||||||
;File "${MING_BIN}\libpng15-15.dll"
|
;File "${MING_BIN}\libpng15-15.dll"
|
||||||
;File "${MING_BIN}\libjpeg-8.dll"
|
File "${MING_BIN}\libjpeg-8.dll"
|
||||||
File "${MING_BIN}\zlib1.dll"
|
File "${MING_BIN}\zlib1.dll"
|
||||||
File "${MING_BIN}\libcrypto-10.dll"
|
File "${MING_BIN}\libcrypto-10.dll"
|
||||||
File "${MING_BIN}\libssl-10.dll"
|
File "${MING_BIN}\libssl-10.dll"
|
||||||
@@ -455,17 +391,6 @@ SectionGroup "Shortcuts"
|
|||||||
|
|
||||||
SectionGroupEnd
|
SectionGroupEnd
|
||||||
|
|
||||||
!ifdef OPTION_SECTION_SC_AUTOSTART
|
|
||||||
${MementoSection} "Autostart" SEC_AUTOSTART
|
|
||||||
SectionIn 1 2
|
|
||||||
SetDetailsPrint textonly
|
|
||||||
DetailPrint "Creating Windows Start Entry"
|
|
||||||
SetDetailsPrint listonly
|
|
||||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Run" \
|
|
||||||
"${APPLICATION_NAME}" "$INSTDIR\${APPLICATION_EXECUTABLE}"
|
|
||||||
${MementoSectionEnd}
|
|
||||||
!endif
|
|
||||||
|
|
||||||
${MementoSectionDone}
|
${MementoSectionDone}
|
||||||
|
|
||||||
; Installer section descriptions
|
; Installer section descriptions
|
||||||
@@ -475,7 +400,6 @@ ${MementoSectionDone}
|
|||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} program group."
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} program group."
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}."
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}."
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}."
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}."
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_AUTOSTART} "Register ${APPLICATION_NAME} to run on Windows startup."
|
|
||||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||||
|
|
||||||
Section -post
|
Section -post
|
||||||
@@ -578,11 +502,6 @@ Section Uninstall
|
|||||||
|
|
||||||
DeleteRegKey HKCR "${APPLICATION_NAME}"
|
DeleteRegKey HKCR "${APPLICATION_NAME}"
|
||||||
|
|
||||||
;Windows Start entry
|
|
||||||
!ifdef OPTION_SECTION_SC_AUTOSTART
|
|
||||||
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPLICATION_NAME}"
|
|
||||||
!endif
|
|
||||||
|
|
||||||
;Start menu shortcuts.
|
;Start menu shortcuts.
|
||||||
!ifdef OPTION_SECTION_SC_START_MENU
|
!ifdef OPTION_SECTION_SC_START_MENU
|
||||||
SetShellVarContext all
|
SetShellVarContext all
|
||||||
|
|||||||
20
cmake/modules/Warnings.cmake
Normal file
20
cmake/modules/Warnings.cmake
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||||
|
OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
if(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||||
|
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Wno-long-long")
|
||||||
|
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||||
|
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
|
||||||
|
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
if(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
|
||||||
|
endif(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||||
|
# TODO: handle msvc compilers warnings?
|
||||||
|
|
||||||
|
if(DEFINED MIRALL_FATAL_WARNINGS)
|
||||||
|
if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||||
|
endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
|
||||||
|
# TODO: handle msvc compilers warnings?
|
||||||
|
endif(DEFINED MIRALL_FATAL_WARNINGS)
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#cmakedefine USE_INOTIFY 1
|
#cmakedefine USE_INOTIFY 1
|
||||||
#cmakedefine WITH_CSYNC 1
|
|
||||||
#cmakedefine WITH_QTKEYCHAIN 1
|
#cmakedefine WITH_QTKEYCHAIN 1
|
||||||
|
|
||||||
#cmakedefine GIT_SHA1 "@GIT_SHA1@"
|
#cmakedefine GIT_SHA1 "@GIT_SHA1@"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ if(SPHINX_FOUND)
|
|||||||
# apt-get install texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
|
# apt-get install texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
|
||||||
add_custom_target(doc-latex ${SPHINX_EXECUTABLE}
|
add_custom_target(doc-latex ${SPHINX_EXECUTABLE}
|
||||||
-q -c . -b latex
|
-q -c . -b latex
|
||||||
-d ${SPHINX_CACHE_DIR}
|
-d ${SPHINX_CACHE_DIR}/latex
|
||||||
-D latex_logo=${LATEX_LOGO}
|
-D latex_logo=${LATEX_LOGO}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${SPHINX_PDF_DIR} )
|
${SPHINX_PDF_DIR} )
|
||||||
@@ -41,7 +41,7 @@ if(SPHINX_FOUND)
|
|||||||
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
|
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
|
||||||
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
|
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
|
||||||
-q -c . -b qthelp
|
-q -c . -b qthelp
|
||||||
-d ${SPHINX_CACHE_DIR}
|
-d ${SPHINX_CACHE_DIR}/qthelp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${SPHINX_QCH_DIR} )
|
${SPHINX_QCH_DIR} )
|
||||||
add_custom_target( doc-qch ${QT_QCOLLECTIONGENERATOR_EXECUTABLE}
|
add_custom_target( doc-qch ${QT_QCOLLECTIONGENERATOR_EXECUTABLE}
|
||||||
@@ -54,12 +54,12 @@ if(SPHINX_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
|
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
|
||||||
-q -c . -b html
|
-q -c . -b html
|
||||||
-d ${SPHINX_CACHE_DIR}
|
-d ${SPHINX_CACHE_DIR}/html
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${SPHINX_HTML_DIR} )
|
${SPHINX_HTML_DIR} )
|
||||||
add_custom_target( doc-man ${SPHINX_EXECUTABLE}
|
add_custom_target( doc-man ${SPHINX_EXECUTABLE}
|
||||||
-q -c . -b man
|
-q -c . -b man
|
||||||
-d ${SPHINX_CACHE_DIR}
|
-d ${SPHINX_CACHE_DIR}/man
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${SPHINX_MAN_DIR} )
|
${SPHINX_MAN_DIR} )
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ if(SPHINX_FOUND)
|
|||||||
add_custom_target( doc-chm-sphinx ${SPHINX_EXECUTABLE}
|
add_custom_target( doc-chm-sphinx ${SPHINX_EXECUTABLE}
|
||||||
-q -c . -b htmlhelp
|
-q -c . -b htmlhelp
|
||||||
-D html_theme=basic
|
-D html_theme=basic
|
||||||
-d ${SPHINX_CACHE_DIR}
|
-d ${SPHINX_CACHE_DIR}/htmlhelp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${SPHINX_HTMLHELP_DIR} )
|
${SPHINX_HTMLHELP_DIR} )
|
||||||
add_custom_target( doc-chm pushd ${SPHINX_HTMLHELP_DIR}; ${MSHTML_COMPILER} *.hhp; popd
|
add_custom_target( doc-chm pushd ${SPHINX_HTMLHELP_DIR}; ${MSHTML_COMPILER} *.hhp; popd
|
||||||
|
|||||||
@@ -34,8 +34,13 @@ server is always master.
|
|||||||
This is the major difference to other systems like a file backup where just
|
This is the major difference to other systems like a file backup where just
|
||||||
changes and new files are propagated but files never get deleted.
|
changes and new files are propagated but files never get deleted.
|
||||||
|
|
||||||
Sync Direction and Strategies
|
The oCC checks both repositories for changes frequently after a certain time
|
||||||
-----------------------------
|
span. That is refered to as a sync run. In between the local repository is
|
||||||
|
monitored by a file system monitor system that starts a sync run immediately
|
||||||
|
if something was edited, added or removed.
|
||||||
|
|
||||||
|
Sync by Time versus ETag
|
||||||
|
------------------------
|
||||||
.. index:: time stamps, file times, etag, unique id
|
.. index:: time stamps, file times, etag, unique id
|
||||||
|
|
||||||
Until the release of ownCloud 4.5 and ownCloud Client 1.1, ownCloud employed
|
Until the release of ownCloud 4.5 and ownCloud Client 1.1, ownCloud employed
|
||||||
@@ -44,7 +49,7 @@ synced to the other repository: the files modification time.
|
|||||||
|
|
||||||
The *modification timestamp* is part of the files metadata. It is available on
|
The *modification timestamp* is part of the files metadata. It is available on
|
||||||
every relevant filesystem and is the natural indicator for a file change.
|
every relevant filesystem and is the natural indicator for a file change.
|
||||||
modification timestamps do not require special action to create and have
|
Modification timestamps do not require special action to create and have
|
||||||
a general meaning. One design goal of csync is to not require a special server
|
a general meaning. One design goal of csync is to not require a special server
|
||||||
component, that’s why it was chosen as the backend component.
|
component, that’s why it was chosen as the backend component.
|
||||||
|
|
||||||
@@ -57,29 +62,22 @@ machines.
|
|||||||
Since this strategy is rather fragile without NTP, ownCloud 4.5 introduced a
|
Since this strategy is rather fragile without NTP, ownCloud 4.5 introduced a
|
||||||
unique number, which changes whenever the file changes. Although it is a unique
|
unique number, which changes whenever the file changes. Although it is a unique
|
||||||
value, it is not a hash of the file, but a randomly chosen number, which it will
|
value, it is not a hash of the file, but a randomly chosen number, which it will
|
||||||
transmit in the Etag_ field. The client will store this number in a
|
transmit in the Etag_ field. Since the file number is guaranteed to change if the
|
||||||
per-directory database, located in the application directory (version 1.1) or
|
file changes, it can now be used to determine if one of the files has changed.
|
||||||
as a hidden file right in the directory to be synced (later versions).
|
|
||||||
Since the file number is guaranteed to change if the file changes, it can now be
|
|
||||||
used to determine if one of the files has changed.
|
|
||||||
|
|
||||||
.. todo:: describe what happens if both sides change
|
.. note:: oCC 1.1 and newer require file ID capabilities on the ownCloud server,
|
||||||
|
hence using them with a server earlier than 4.5.0 is not supported.
|
||||||
|
|
||||||
|
Before the 1.3.0 release of the client the sync process might create faux conflict
|
||||||
|
files if time deviates. The original and the conflict files only differed in the
|
||||||
|
timestamp, but not in content. This behaviour was changed towards a binary check
|
||||||
|
if the files are different.
|
||||||
|
|
||||||
If the per-directory database gets removed, oCC's CSync backend will fall back
|
|
||||||
to a time-stamp based sync process to rebuild the database. Thus it should be
|
|
||||||
made sure that both server and client synchronized to NTP time before
|
|
||||||
restarting the client after a database removal. If time deviates, the sync
|
|
||||||
process might create faux conflict files, which only differ in their time.
|
|
||||||
Those need to be cleaned up manually later on and will not be synced back
|
|
||||||
to the server. However, no files will get deleted in this process.
|
|
||||||
|
|
||||||
Just like files, directories also hold a unique id, which changes whenever
|
Just like files, directories also hold a unique id, which changes whenever
|
||||||
one of the contained files or directories gets modified. Since this is a
|
one of the contained files or directories gets modified. Since this is a
|
||||||
recursive process, it significantly reduces the effort required for a sync
|
recursive process, it significantly reduces the effort required for a sync
|
||||||
cycle, because the client will only walk directories with a modified unique id.
|
cycle, because the client will only walk directories with a modified unique id.
|
||||||
|
|
||||||
.. note:: oCC 1.1 and newer require file ID capabilities on the ownCloud server,
|
|
||||||
hence using them with a server earlier than 4.5.0 is not supported.
|
|
||||||
|
|
||||||
This table outlines the different sync methods attempted depending
|
This table outlines the different sync methods attempted depending
|
||||||
on server/client combination:
|
on server/client combination:
|
||||||
@@ -106,3 +104,39 @@ are involved and one of them is not in sync with NTP time.
|
|||||||
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
|
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
|
||||||
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
|
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
|
||||||
|
|
||||||
|
Comparison and Conflict Cases
|
||||||
|
----------------------------
|
||||||
|
In a sync run the client first has to detect if one of the two repositories have
|
||||||
|
changed files. On the local repository, the client traverses the file
|
||||||
|
tree and compares the modification time of each file with the value it was
|
||||||
|
before. The previous value is stored in the client's database. If it is not, it
|
||||||
|
means that the file has been added to the local repository. Note that on
|
||||||
|
the local side, the modificaton time a good attribute to detect changes because
|
||||||
|
it does not depend on time shifts and such.
|
||||||
|
|
||||||
|
For the remote (ie. ownCloud) repository, the client compares the ETag of each
|
||||||
|
file with it's previous value. Again the previous value is queried from the
|
||||||
|
database. If the ETag is still the same, the file has not changed.
|
||||||
|
|
||||||
|
So what happens if a file has changed on both, the local and the remote repository
|
||||||
|
since the last sync run? That means it can not easily be decided which version
|
||||||
|
of the file is the one that should be used. Moreover, changes to any side must
|
||||||
|
not be lost. That is called the conflict case and the client solves it by creating
|
||||||
|
a conflict file of the older of the two files and save the newer one under the
|
||||||
|
original file name. Conflict files are always created on the client and never on
|
||||||
|
the server. The conflict file has the same name as the original file appended
|
||||||
|
with the timestamp of the conflict detection.
|
||||||
|
|
||||||
|
The Sync Journal
|
||||||
|
----------------
|
||||||
|
The client stores the ETag number in a per-directory database, called the journal.
|
||||||
|
It is located in the application directory (until version 1.1) or as a hidden file
|
||||||
|
right in the directory to be synced (later versions).
|
||||||
|
|
||||||
|
If the journal database gets removed, oCC's CSync backend will rebuild the database
|
||||||
|
by comparing the files and their modification times. Thus it should be made sure
|
||||||
|
that both server and client synchronized to NTP time before restarting the client
|
||||||
|
after a database removal.
|
||||||
|
|
||||||
|
The oCC also provides a button in the Settings Dialog that allows to "reset" the
|
||||||
|
journal. That can be used to recreate the journal database.
|
||||||
@@ -37,7 +37,7 @@ Next, install the missing dependencies::
|
|||||||
brew install $(brew deps ocsync)
|
brew install $(brew deps ocsync)
|
||||||
brew install $(brew deps mirall)
|
brew install $(brew deps mirall)
|
||||||
|
|
||||||
To build mirall and cmake, follow the `generic build instructions`_.
|
To build mirall and csync, follow the `generic build instructions`_.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
You should not call ``make install`` at any time, since the product of the
|
You should not call ``make install`` at any time, since the product of the
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
ownCloud Client supports the following command line switches:
|
ownCloud Client supports the following command line switches:
|
||||||
|
|
||||||
``--logwindow``
|
``--logwindow``
|
||||||
open a window to show log output at startup.
|
open a window to show log output.
|
||||||
|
|
||||||
``--logfile`` `<file>`
|
``--logfile`` `<filename>`
|
||||||
write log output to a single file
|
write log output to file <filename>.
|
||||||
|
|
||||||
``--logdir`` `<dir>`
|
``--logdir`` `<name>`
|
||||||
write log output to dir, one for each sync run.
|
write each sync log output in a new file in directory <name>
|
||||||
|
|
||||||
``--flushlog``
|
``--logexpire`` `<hours>`
|
||||||
|
removes logs older than <hours> hours. (to be used with --logdir)
|
||||||
|
|
||||||
|
``--logflush``
|
||||||
flush the log file after every write.
|
flush the log file after every write.
|
||||||
|
|
||||||
``--monoicons``
|
``--monoicons``
|
||||||
Use black/white pictograms for systray.
|
Use black/white pictograms for systray.
|
||||||
|
|
||||||
|
``--confdir`` `<dirname>`
|
||||||
|
Use the given configuration directory.
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,16 @@ create a huge amount of data, as the log window has a limited buffer.
|
|||||||
To write logs to disk, start the client with ``--logfile <file>``, where
|
To write logs to disk, start the client with ``--logfile <file>``, where
|
||||||
``<file`` is the file you want to log to, or ``--logdir <dir>``, where ``<dir>``
|
``<file`` is the file you want to log to, or ``--logdir <dir>``, where ``<dir>``
|
||||||
is an existing directory. In case of ``--logdir``, each sync run will create a
|
is an existing directory. In case of ``--logdir``, each sync run will create a
|
||||||
new file.
|
new file. To limit the amount of data that accumulates over time, there is another
|
||||||
|
useful parameter: ``--logexpire <hours>```. If that is combined with ```--logdir```
|
||||||
|
the client automatically erases log data in that directory that is older than the
|
||||||
|
given expiry period.
|
||||||
|
|
||||||
|
For example, for a long running test where you intend to keep the log data of the
|
||||||
|
last two days, this would be the command line:
|
||||||
|
```
|
||||||
|
owncloud --logdir /tmp/owncloud_logs --logexpire 48
|
||||||
|
```
|
||||||
|
|
||||||
:ownCloud server Logfile:
|
:ownCloud server Logfile:
|
||||||
The ownCloud server maintains an ownCloud specific logfile as well. It can and
|
The ownCloud server maintains an ownCloud specific logfile as well. It can and
|
||||||
|
|||||||
@@ -26,23 +26,63 @@ also opens the status dialog.
|
|||||||
The dialog provides an overview on the configured sync folders and allows to add
|
The dialog provides an overview on the configured sync folders and allows to add
|
||||||
and remove more sync folder connections as well as pausing a sync connection.
|
and remove more sync folder connections as well as pausing a sync connection.
|
||||||
|
|
||||||
Changing your password
|
Changing Your Password and Account Settings
|
||||||
----------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Use the ``Configure`` option. It will open the Connection Wizard, which next to
|
In the ``Settings`` Dialog, choose ``Account`` -> ``Modify Account``. It will open
|
||||||
reconfiguring your connection to use a different user or server also will allow
|
Setup Wizard, which next to reconfiguring your connection to use a different
|
||||||
to change the password for the local account, or to switch from HTTP to HTTPS.
|
user or server also will allow to change the password for the local account,
|
||||||
|
or to switch from HTTP to HTTPS.
|
||||||
|
|
||||||
Setting up a proxy
|
Setting up a Proxy
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
By default, the configured system proxy will be picked up. This may not be
|
By default, the configured system proxy will be picked up. This may not be
|
||||||
working reliable on some Linux distributions, as only the ``http_proxy``
|
working reliably on some Linux distributions, as only the ``http_proxy``
|
||||||
variable gets parsed. You can configure a proxy different from your
|
variable gets picked up. You can configure a proxy different from your
|
||||||
system default by choosing ``Configure proxy...`` from the menu.
|
system default in the ``Network`` section of the ``Settings`` dialog.
|
||||||
|
|
||||||
By default, ownCloud expects a HTTP proxy. If you want to specify a SOCKS5
|
The default settings assume an HTTP proxy, which is the typical use case.
|
||||||
proxy instead, tick the "Use as SOCKSv5 proxy" option.
|
If you require SOCKS 5 proxy, pick ``SOCKS5 proxy`` instead of ``HTTP(S) proxy``
|
||||||
|
from the drop down menu. SOCKS 5 proxies are typically provided by some
|
||||||
|
SSH implementations, for instance OpenSSH's ``-D`` parameter. This is
|
||||||
|
useful for scenarios where SSH is employed to securely tunnel a client
|
||||||
|
to the network running the ownCloud server.
|
||||||
|
|
||||||
|
Limiting Bandwidth
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Starting with Version 1.4, the Client provides bandwidth limiter.
|
||||||
|
This option can be found in the ``Network`` section of the
|
||||||
|
``Settings Dialog``.
|
||||||
|
|
||||||
|
You will find two settings for ``Download Bandwidth`` and
|
||||||
|
``Upload Bandwidth``.
|
||||||
|
|
||||||
|
Upload Bandwidth
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The default is to automatically limit the upload. The rationale
|
||||||
|
for this default is that typically, Computers and laptops are
|
||||||
|
not directly connected to the server, but via a Cable Modems
|
||||||
|
or DSL lines, which provide significantly more downstream than
|
||||||
|
upstream bandwith. Sataurating the upstream bandwidth would
|
||||||
|
interfere with other applications, especially Voice-Over-IP or
|
||||||
|
Games.
|
||||||
|
|
||||||
|
The automatic limiter will throttle the speed to about 75%
|
||||||
|
of the available upstream bandwidth. If you are communicating
|
||||||
|
with the server via a fast, symetric connection, you can set the
|
||||||
|
Limiter to ``No Limit`` instead. If want a stronger limitation,
|
||||||
|
choose ``Limit to`` and specify a limit manually.
|
||||||
|
|
||||||
|
|
||||||
|
Download Bandwidth
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Because the download bandwidth is usually no concern, it is not
|
||||||
|
automatically limited. Should you find that the Client is taking
|
||||||
|
up too much bandwidth, you can manually specify a limit (in KB).
|
||||||
|
|
||||||
Options
|
Options
|
||||||
-------
|
-------
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ Exec=@APPLICATION_EXECUTABLE@
|
|||||||
Name=@APPLICATION_NAME@ desktop sync client
|
Name=@APPLICATION_NAME@ desktop sync client
|
||||||
GenericName=Folder Sync
|
GenericName=Folder Sync
|
||||||
Icon=@APPLICATION_SHORTNAME@
|
Icon=@APPLICATION_SHORTNAME@
|
||||||
|
Keywords=@APPLICATION_NAME@;syncing;file;sharing
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
<file>resources/task-ongoing.png</file>
|
<file>resources/task-ongoing.png</file>
|
||||||
<file>resources/view-refresh.png</file>
|
<file>resources/view-refresh.png</file>
|
||||||
<file>resources/warning-16.png</file>
|
<file>resources/warning-16.png</file>
|
||||||
|
<file>resources/settings.png</file>
|
||||||
|
<file>resources/network.png</file>
|
||||||
<file>resources/owncloud_logo_blue.png</file>
|
<file>resources/owncloud_logo_blue.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
BIN
resources/network.png
Normal file
BIN
resources/network.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/settings.png
Normal file
BIN
resources/settings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -11,16 +11,22 @@ else()
|
|||||||
set(theme_dir ${CMAKE_CURRENT_SOURCE_DIR}/../theme)
|
set(theme_dir ${CMAKE_CURRENT_SOURCE_DIR}/../theme)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(synclib_NAME ${APPLICATION_SHORTNAME}sync)
|
||||||
|
|
||||||
set(mirall_UI
|
set(mirall_UI
|
||||||
mirall/folderwizardsourcepage.ui
|
mirall/folderwizardsourcepage.ui
|
||||||
mirall/folderwizardtargetpage.ui
|
mirall/folderwizardtargetpage.ui
|
||||||
mirall/statusdialog.ui
|
|
||||||
mirall/owncloudsetuppage_ng.ui
|
|
||||||
mirall/owncloudwizardresultpage.ui
|
|
||||||
mirall/owncloudcredentialspage.ui
|
|
||||||
mirall/sslerrordialog.ui
|
mirall/sslerrordialog.ui
|
||||||
mirall/proxydialog.ui
|
mirall/settingsdialog.ui
|
||||||
mirall/fileitemdialog.ui
|
mirall/generalsettings.ui
|
||||||
|
mirall/networksettings.ui
|
||||||
|
mirall/accountsettings.ui
|
||||||
|
mirall/ignorelisteditor.ui
|
||||||
|
mirall/itemprogressdialog.ui
|
||||||
|
wizard/owncloudsetupnocredspage.ui
|
||||||
|
wizard/owncloudhttpcredspage.ui
|
||||||
|
wizard/owncloudwizardresultpage.ui
|
||||||
|
wizard/owncloudadvancedsetuppage.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
set(3rdparty_SRC
|
set(3rdparty_SRC
|
||||||
@@ -63,8 +69,6 @@ set(libsync_SRCS
|
|||||||
mirall/syncresult.cpp
|
mirall/syncresult.cpp
|
||||||
mirall/networklocation.cpp
|
mirall/networklocation.cpp
|
||||||
mirall/mirallconfigfile.cpp
|
mirall/mirallconfigfile.cpp
|
||||||
mirall/credentialstore.cpp
|
|
||||||
mirall/owncloudfolder.cpp
|
|
||||||
mirall/csyncthread.cpp
|
mirall/csyncthread.cpp
|
||||||
mirall/fileutils.cpp
|
mirall/fileutils.cpp
|
||||||
mirall/theme.cpp
|
mirall/theme.cpp
|
||||||
@@ -73,17 +77,47 @@ set(libsync_SRCS
|
|||||||
mirall/logger.cpp
|
mirall/logger.cpp
|
||||||
mirall/utility.cpp
|
mirall/utility.cpp
|
||||||
mirall/connectionvalidator.cpp
|
mirall/connectionvalidator.cpp
|
||||||
|
mirall/progressdispatcher.cpp
|
||||||
|
mirall/mirallaccessmanager.cpp
|
||||||
|
creds/dummycredentials.cpp
|
||||||
|
creds/httpcredentials.cpp
|
||||||
|
creds/credentialsfactory.cpp
|
||||||
|
creds/http/credentialstore.cpp
|
||||||
|
creds/http/httpconfigfile.cpp
|
||||||
|
creds/shibbolethcredentials.cpp
|
||||||
|
creds/shibboleth/shibbolethaccessmanager.cpp
|
||||||
|
creds/shibboleth/shibbolethcookiejar.cpp
|
||||||
|
creds/shibboleth/shibbolethwebview.cpp
|
||||||
|
creds/shibboleth/shibbolethrefresher.cpp
|
||||||
|
creds/shibboleth/shibbolethconfigfile.cpp
|
||||||
|
creds/credentialscommon.cpp
|
||||||
)
|
)
|
||||||
set(libsync_HEADERS
|
|
||||||
|
set(libsync_HEADERS
|
||||||
mirall/folderman.h
|
mirall/folderman.h
|
||||||
mirall/folder.h
|
mirall/folder.h
|
||||||
mirall/folderwatcher.h
|
mirall/folderwatcher.h
|
||||||
mirall/owncloudfolder.h
|
|
||||||
mirall/csyncthread.h
|
mirall/csyncthread.h
|
||||||
|
mirall/theme.h
|
||||||
|
mirall/owncloudtheme.h
|
||||||
mirall/owncloudinfo.h
|
mirall/owncloudinfo.h
|
||||||
mirall/credentialstore.h
|
|
||||||
mirall/logger.h
|
mirall/logger.h
|
||||||
mirall/connectionvalidator.h
|
mirall/connectionvalidator.h
|
||||||
|
mirall/progressdispatcher.h
|
||||||
|
mirall/mirallaccessmanager.h
|
||||||
|
creds/abstractcredentials.h
|
||||||
|
creds/dummycredentials.h
|
||||||
|
creds/httpcredentials.h
|
||||||
|
creds/credentialsfactory.h
|
||||||
|
creds/http/credentialstore.h
|
||||||
|
creds/http/httpconfigfile.h
|
||||||
|
creds/shibbolethcredentials.h
|
||||||
|
creds/shibboleth/shibbolethaccessmanager.h
|
||||||
|
creds/shibboleth/shibbolethcookiejar.h
|
||||||
|
creds/shibboleth/shibbolethwebview.h
|
||||||
|
creds/shibboleth/shibbolethrefresher.h
|
||||||
|
creds/shibboleth/shibbolethconfigfile.h
|
||||||
|
creds/credentialscommon.h
|
||||||
)
|
)
|
||||||
|
|
||||||
IF( INOTIFY_FOUND )
|
IF( INOTIFY_FOUND )
|
||||||
@@ -114,20 +148,20 @@ if(QTKEYCHAIN_FOUND)
|
|||||||
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
|
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(owncloudsync SHARED ${libsync_SRCS} ${syncMoc})
|
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
|
||||||
set_target_properties( owncloudsync PROPERTIES
|
set_target_properties( ${synclib_NAME} PROPERTIES
|
||||||
VERSION ${VERSION}
|
VERSION ${VERSION}
|
||||||
SOVERSION ${SOVERSION}
|
SOVERSION ${SOVERSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(owncloudsync ${libsync_LINK_TARGETS} )
|
target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} )
|
||||||
|
|
||||||
if ( APPLE )
|
if ( APPLE )
|
||||||
target_link_libraries(owncloudsync /System/Library/Frameworks/CoreServices.framework)
|
target_link_libraries(${synclib_NAME} /System/Library/Frameworks/CoreServices.framework)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||||
install(TARGETS owncloudsync
|
install(TARGETS ${synclib_NAME}
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
@@ -138,22 +172,32 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
|||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_SHORTNAME}.desktop DESTINATION share/applications )
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_SHORTNAME}.desktop DESTINATION share/applications )
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
install(TARGETS owncloudsync DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
|
install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(mirall_SRCS
|
set(mirall_SRCS
|
||||||
mirall/application.cpp
|
mirall/application.cpp
|
||||||
mirall/systray.cpp
|
mirall/systray.cpp
|
||||||
mirall/folderwizard.cpp
|
mirall/folderwizard.cpp
|
||||||
mirall/statusdialog.cpp
|
mirall/folderstatusmodel.cpp
|
||||||
mirall/owncloudwizard.cpp
|
wizard/owncloudwizard.cpp
|
||||||
|
wizard/owncloudsetuppage.cpp
|
||||||
|
wizard/owncloudhttpcredspage.cpp
|
||||||
|
wizard/owncloudwizardresultpage.cpp
|
||||||
|
wizard/owncloudwizardcommon.cpp
|
||||||
|
wizard/owncloudshibbolethcredspage.cpp
|
||||||
|
wizard/owncloudadvancedsetuppage.cpp
|
||||||
mirall/owncloudsetupwizard.cpp
|
mirall/owncloudsetupwizard.cpp
|
||||||
mirall/updatedetector.cpp
|
mirall/updatedetector.cpp
|
||||||
mirall/occinfo.cpp
|
mirall/occinfo.cpp
|
||||||
mirall/sslerrordialog.cpp
|
mirall/sslerrordialog.cpp
|
||||||
mirall/logbrowser.cpp
|
mirall/logbrowser.cpp
|
||||||
mirall/proxydialog.cpp
|
mirall/settingsdialog.cpp
|
||||||
mirall/fileitemdialog.cpp
|
mirall/generalsettings.cpp
|
||||||
|
mirall/networksettings.cpp
|
||||||
|
mirall/accountsettings.cpp
|
||||||
|
mirall/ignorelisteditor.cpp
|
||||||
|
mirall/itemprogressdialog.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(mirall_HEADERS
|
set(mirall_HEADERS
|
||||||
@@ -161,13 +205,23 @@ set(mirall_HEADERS
|
|||||||
mirall/systray.h
|
mirall/systray.h
|
||||||
mirall/folderwizard.h
|
mirall/folderwizard.h
|
||||||
mirall/owncloudsetupwizard.h
|
mirall/owncloudsetupwizard.h
|
||||||
mirall/owncloudwizard.h
|
wizard/owncloudwizard.h
|
||||||
mirall/statusdialog.h
|
wizard/owncloudsetuppage.h
|
||||||
|
wizard/owncloudhttpcredspage.h
|
||||||
|
wizard/owncloudwizardresultpage.h
|
||||||
|
wizard/owncloudwizardcommon.h
|
||||||
|
wizard/owncloudshibbolethcredspage.h
|
||||||
|
wizard/owncloudadvancedsetuppage.h
|
||||||
|
mirall/folderstatusmodel.h
|
||||||
mirall/updatedetector.h
|
mirall/updatedetector.h
|
||||||
mirall/sslerrordialog.h
|
mirall/sslerrordialog.h
|
||||||
mirall/logbrowser.h
|
mirall/logbrowser.h
|
||||||
mirall/proxydialog.h
|
mirall/settingsdialog.h
|
||||||
mirall/fileitemdialog.h
|
mirall/generalsettings.h
|
||||||
|
mirall/networksettings.h
|
||||||
|
mirall/accountsettings.h
|
||||||
|
mirall/ignorelisteditor.h
|
||||||
|
mirall/itemprogressdialog.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if( UNIX AND NOT APPLE)
|
if( UNIX AND NOT APPLE)
|
||||||
@@ -208,12 +262,16 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
|||||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
install(FILES
|
file( GLOB _icons "${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-*.png" )
|
||||||
${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-48.png
|
foreach( _file ${_icons} )
|
||||||
DESTINATION share/icons/hicolor/48x48/apps/ RENAME ${APPLICATION_SHORTNAME}.png)
|
string( REPLACE "${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-" "" _res ${_file} )
|
||||||
|
string( REPLACE ".png" "" _res ${_res} )
|
||||||
|
install( FILES ${_file} RENAME ${APPLICATION_SHORTNAME}.png DESTINATION
|
||||||
|
${CMAKE_INSTALL_DATADIR}/icons/hicolor/${_res}x${_res}/apps )
|
||||||
|
endforeach( _file )
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
install(FILES ${mirall_I18N} DESTINATION share/mirall/i18n)
|
install(FILES ${mirall_I18N} DESTINATION share/${APPLICATION_SHORTNAME}/i18n)
|
||||||
|
|
||||||
# we may not add MACOSX_BUNDLE here, if not building one
|
# we may not add MACOSX_BUNDLE here, if not building one
|
||||||
|
|
||||||
@@ -251,7 +309,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
|
|||||||
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
|
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
|
||||||
)
|
)
|
||||||
target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
|
target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
|
||||||
target_link_libraries( ${APPLICATION_EXECUTABLE} owncloudsync )
|
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
|
||||||
target_link_libraries( ${APPLICATION_EXECUTABLE} ${CSYNC_LIBRARY} )
|
target_link_libraries( ${APPLICATION_EXECUTABLE} ${CSYNC_LIBRARY} )
|
||||||
|
|
||||||
install(TARGETS ${APPLICATION_EXECUTABLE}
|
install(TARGETS ${APPLICATION_EXECUTABLE}
|
||||||
|
|||||||
47
src/creds/abstractcredentials.h
Normal file
47
src/creds/abstractcredentials.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_ABSTRACT_CREDENTIALS_H
|
||||||
|
#define MIRALL_CREDS_ABSTRACT_CREDENTIALS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <csync.h>
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class AbstractCredentials : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
// No need for virtual destructor - QObject already has one.
|
||||||
|
virtual void syncContextPreInit(CSYNC* ctx) = 0;
|
||||||
|
virtual void syncContextPreStart(CSYNC* ctx) = 0;
|
||||||
|
virtual bool changed(AbstractCredentials* credentials) const = 0;
|
||||||
|
virtual QString authType() const = 0;
|
||||||
|
virtual QNetworkAccessManager* getQNAM() const = 0;
|
||||||
|
virtual bool ready() const = 0;
|
||||||
|
virtual void fetch() = 0;
|
||||||
|
virtual void persistForUrl(const QString& url) = 0;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void fetched();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
77
src/creds/credentialscommon.cpp
Normal file
77
src/creds/credentialscommon.cpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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 <QList>
|
||||||
|
#include <QRegExp>
|
||||||
|
#include <QString>
|
||||||
|
#include <QSslCertificate>
|
||||||
|
|
||||||
|
#include "creds/credentialscommon.h"
|
||||||
|
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/owncloudinfo.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
int handleNeonSSLProblems(const char* prompt,
|
||||||
|
char* buf,
|
||||||
|
size_t /*len*/,
|
||||||
|
int /*echo*/,
|
||||||
|
int /*verify*/,
|
||||||
|
void* /*userdata*/)
|
||||||
|
{
|
||||||
|
int re = 0;
|
||||||
|
const QString qPrompt = QString::fromLatin1( prompt ).trimmed();
|
||||||
|
|
||||||
|
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
|
||||||
|
// SSL is requested. If the program came here, the SSL check was done by mirall
|
||||||
|
// It needs to be checked if the chain is still equal to the one which
|
||||||
|
// was verified by the user.
|
||||||
|
const QRegExp regexp("fingerprint: ([\\w\\d:]+)");
|
||||||
|
bool certOk = false;
|
||||||
|
int pos = 0;
|
||||||
|
// This is the set of certificates which QNAM accepted, so we should accept
|
||||||
|
// them as well
|
||||||
|
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
|
||||||
|
|
||||||
|
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
|
||||||
|
QString neon_fingerprint = regexp.cap(1);
|
||||||
|
|
||||||
|
foreach( const QSslCertificate& c, certs ) {
|
||||||
|
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
|
||||||
|
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
|
||||||
|
if( verified_shasum == neon_fingerprint ) {
|
||||||
|
certOk = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// certOk = false; DEBUG setting, keep disabled!
|
||||||
|
if( !certOk ) { // Problem!
|
||||||
|
qstrcpy( buf, "no" );
|
||||||
|
re = -1;
|
||||||
|
} else {
|
||||||
|
qstrcpy( buf, "yes" ); // Certificate is fine!
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Unknown prompt: <" << prompt << ">";
|
||||||
|
re = -1;
|
||||||
|
}
|
||||||
|
return re;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
32
src/creds/credentialscommon.h
Normal file
32
src/creds/credentialscommon.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_COMMON_H
|
||||||
|
#define MIRALL_CREDS_COMMON_H
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
int handleNeonSSLProblems(const char* prompt,
|
||||||
|
char* buf,
|
||||||
|
size_t len,
|
||||||
|
int echo,
|
||||||
|
int verify,
|
||||||
|
void* userdata);
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
43
src/creds/credentialsfactory.cpp
Normal file
43
src/creds/credentialsfactory.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "creds/httpcredentials.h"
|
||||||
|
#include "creds/dummycredentials.h"
|
||||||
|
#include "creds/shibbolethcredentials.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace CredentialsFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
AbstractCredentials* create(const QString& type)
|
||||||
|
{
|
||||||
|
// empty string might happen for old version of configuration
|
||||||
|
if (type == "http" || type == "") {
|
||||||
|
return new HttpCredentials;
|
||||||
|
} else if (type == "dummy") {
|
||||||
|
return new DummyCredentials;
|
||||||
|
} else if (type == "shibboleth") {
|
||||||
|
return new ShibbolethCredentials;
|
||||||
|
} else {
|
||||||
|
qWarning("Unknown credentials type: %s", qPrintable(type));
|
||||||
|
return new DummyCredentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns CredentialsFactory
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
32
src/creds/credentialsfactory.h
Normal file
32
src/creds/credentialsfactory.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_CREDENTIALS_FACTORY_H
|
||||||
|
#define MIRALL_CREDS_CREDENTIALS_FACTORY_H
|
||||||
|
|
||||||
|
class AbstractCredentials;
|
||||||
|
class QString;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace CredentialsFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
AbstractCredentials* create(const QString& type);
|
||||||
|
|
||||||
|
} // ns CredentialsFactory
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
56
src/creds/dummycredentials.cpp
Normal file
56
src/creds/dummycredentials.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "creds/dummycredentials.h"
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
void DummyCredentials::syncContextPreInit(CSYNC*)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DummyCredentials::syncContextPreStart(CSYNC*)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool DummyCredentials::changed(AbstractCredentials* credentials) const
|
||||||
|
{
|
||||||
|
DummyCredentials* dummy(dynamic_cast< DummyCredentials* >(credentials));
|
||||||
|
|
||||||
|
return dummy == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DummyCredentials::authType() const
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("dummy");
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager* DummyCredentials::getQNAM() const
|
||||||
|
{
|
||||||
|
return new MirallAccessManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DummyCredentials::ready() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCredentials::fetch()
|
||||||
|
{
|
||||||
|
Q_EMIT(fetched());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyCredentials::persistForUrl(const QString&)
|
||||||
|
{}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
39
src/creds/dummycredentials.h
Normal file
39
src/creds/dummycredentials.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_DUMMY_CREDENTIALS_H
|
||||||
|
#define MIRALL_CREDS_DUMMY_CREDENTIALS_H
|
||||||
|
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class DummyCredentials : public AbstractCredentials
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
void syncContextPreInit(CSYNC* ctx);
|
||||||
|
void syncContextPreStart(CSYNC* ctx);
|
||||||
|
bool changed(AbstractCredentials* credentials) const;
|
||||||
|
QString authType() const;
|
||||||
|
QNetworkAccessManager* getQNAM() const;
|
||||||
|
bool ready() const;
|
||||||
|
void fetch();
|
||||||
|
void persistForUrl(const QString& url);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "mirall/credentialstore.h"
|
#include "creds/http/credentialstore.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "creds/http/httpconfigfile.h"
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
|
|
||||||
#ifdef WITH_QTKEYCHAIN
|
#ifdef WITH_QTKEYCHAIN
|
||||||
@@ -35,7 +35,6 @@ QString CredentialStore::_passwd = QString::null;
|
|||||||
QString CredentialStore::_user = QString::null;
|
QString CredentialStore::_user = QString::null;
|
||||||
QString CredentialStore::_url = QString::null;
|
QString CredentialStore::_url = QString::null;
|
||||||
QString CredentialStore::_errorMsg = QString::null;
|
QString CredentialStore::_errorMsg = QString::null;
|
||||||
int CredentialStore::_tries = 0;
|
|
||||||
#ifdef WITH_QTKEYCHAIN
|
#ifdef WITH_QTKEYCHAIN
|
||||||
CredentialStore::CredentialType CredentialStore::_type = KeyChain;
|
CredentialStore::CredentialType CredentialStore::_type = KeyChain;
|
||||||
#else
|
#else
|
||||||
@@ -67,39 +66,14 @@ CredentialStore::CredState CredentialStore::state()
|
|||||||
return _state;
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CredentialStore::canTryAgain()
|
|
||||||
{
|
|
||||||
if( _tries > MAX_LOGIN_ATTEMPTS ) {
|
|
||||||
qDebug() << "canTryAgain: Max attempts reached.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Since QtKeyChain is required now, it makes sense to only query once. */
|
|
||||||
if( _state == NotFetched || _state == AsyncWriting ) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CredentialStore::fetchCredentials()
|
void CredentialStore::fetchCredentials()
|
||||||
{
|
{
|
||||||
MirallConfigFile cfgFile;
|
HttpConfigFile cfgFile;
|
||||||
if( ++_tries > MAX_LOGIN_ATTEMPTS ) {
|
|
||||||
qDebug() << "Too many attempts to enter password!";
|
|
||||||
_state = TooManyAttempts;
|
|
||||||
emit( fetchCredentialsFinished(false) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
QString pwd;
|
QString pwd;
|
||||||
_user = cfgFile.ownCloudUser();
|
_user = cfgFile.user();
|
||||||
_url = cfgFile.ownCloudUrl();
|
_url = cfgFile.ownCloudUrl();
|
||||||
if( !cfgFile.passwordStorageAllowed() ) {
|
|
||||||
_type = CredentialStore::User;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString key = keyChainKey(_url);
|
QString key = keyChainKey(_url);
|
||||||
|
|
||||||
@@ -111,26 +85,17 @@ void CredentialStore::fetchCredentials()
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch( _type ) {
|
switch( _type ) {
|
||||||
case CredentialStore::User: {
|
|
||||||
/* Ask the user for the password */
|
|
||||||
/* Fixme: Move user interaction out here. */
|
|
||||||
_state = AsyncFetching;
|
|
||||||
_inputDialog = new QInputDialog;
|
|
||||||
_inputDialog->setWindowTitle(QApplication::translate("MirallConfigFile","Password Required") );
|
|
||||||
_inputDialog->setLabelText( QApplication::translate("MirallConfigFile","Please enter your %1 password:")
|
|
||||||
.arg(Theme::instance()->appNameGUI()));
|
|
||||||
_inputDialog->setInputMode( QInputDialog::TextInput );
|
|
||||||
_inputDialog->setTextEchoMode( QLineEdit::Password );
|
|
||||||
|
|
||||||
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
|
|
||||||
_inputDialog->open();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CredentialStore::Settings: {
|
case CredentialStore::Settings: {
|
||||||
/* Read from config file. */
|
/* Read from config file. */
|
||||||
_state = Fetching;
|
_state = Fetching;
|
||||||
pwd = cfgFile.ownCloudPasswd();
|
cfgFile.fixupOldPassword();
|
||||||
ok = true;
|
if( cfgFile.passwordExists() ) {
|
||||||
|
pwd = cfgFile.password();
|
||||||
|
ok = true;
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
_state = EntryNotFound;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CredentialStore::KeyChain: {
|
case CredentialStore::KeyChain: {
|
||||||
@@ -177,25 +142,11 @@ void CredentialStore::fetchCredentials()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CredentialStore::slotUserDialogDone( int result )
|
|
||||||
{
|
|
||||||
if( result == QDialog::Accepted ) {
|
|
||||||
_passwd = _inputDialog->textValue();
|
|
||||||
_state = Ok;
|
|
||||||
} else {
|
|
||||||
_state = UserCanceled;
|
|
||||||
_passwd = QString::null;
|
|
||||||
}
|
|
||||||
_inputDialog->deleteLater();
|
|
||||||
emit(fetchCredentialsFinished(_state == Ok));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CredentialStore::reset()
|
void CredentialStore::reset()
|
||||||
{
|
{
|
||||||
_state = NotFetched;
|
_state = NotFetched;
|
||||||
_user = QString::null;
|
_user = QString::null;
|
||||||
_passwd = QString::null;
|
_passwd = QString::null;
|
||||||
_tries = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CredentialStore::keyChainKey( const QString& url ) const
|
QString CredentialStore::keyChainKey( const QString& url ) const
|
||||||
@@ -242,9 +193,6 @@ void CredentialStore::slotKeyChainReadFinished(QKeychain::Job* job)
|
|||||||
case QKeychain::CouldNotDeleteEntry:
|
case QKeychain::CouldNotDeleteEntry:
|
||||||
_state = Error;
|
_state = Error;
|
||||||
break;
|
break;
|
||||||
case QKeychain::AccessDeniedByUser:
|
|
||||||
_state = AccessDeniedByUser;
|
|
||||||
break;
|
|
||||||
case QKeychain::AccessDenied:
|
case QKeychain::AccessDenied:
|
||||||
_state = AccessDenied;
|
_state = AccessDenied;
|
||||||
break;
|
break;
|
||||||
@@ -293,43 +241,36 @@ QString CredentialStore::errorMessage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CredentialStore::setCredentials( const QString& url, const QString& user,
|
void CredentialStore::setCredentials( const QString& url, const QString& user,
|
||||||
const QString& pwd, bool allowToStore )
|
const QString& pwd )
|
||||||
{
|
{
|
||||||
_passwd = pwd;
|
_passwd = pwd;
|
||||||
_user = user;
|
_user = user;
|
||||||
if( allowToStore ) {
|
|
||||||
#ifdef WITH_QTKEYCHAIN
|
#ifdef WITH_QTKEYCHAIN
|
||||||
_type = KeyChain;
|
_type = KeyChain;
|
||||||
#else
|
#else
|
||||||
_type = Settings;
|
_type = Settings;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
_type = User;
|
|
||||||
}
|
|
||||||
_url = url;
|
_url = url;
|
||||||
_state = Ok;
|
_state = Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CredentialStore::saveCredentials( )
|
void CredentialStore::saveCredentials( )
|
||||||
{
|
{
|
||||||
MirallConfigFile cfgFile;
|
HttpConfigFile cfgFile;
|
||||||
QString key = keyChainKey(_url);
|
QString key = keyChainKey(_url);
|
||||||
if( key.isNull() ) {
|
if( key.isNull() ) {
|
||||||
qDebug() << "Error: Can not save credentials, URL is zero!";
|
qDebug() << "Error: Can not save credentials, URL is zero!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef WITH_QTKEYCHAIN
|
#ifdef WITH_QTKEYCHAIN
|
||||||
WritePasswordJob *job = NULL;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cfgFile.setUser(_user);
|
||||||
switch( _type ) {
|
switch( _type ) {
|
||||||
case CredentialStore::User:
|
case CredentialStore::KeyChain: {
|
||||||
deleteKeyChainCredential( key );
|
|
||||||
break;
|
|
||||||
case CredentialStore::KeyChain:
|
|
||||||
#ifdef WITH_QTKEYCHAIN
|
#ifdef WITH_QTKEYCHAIN
|
||||||
|
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||||
// Set password in KeyChain
|
// Set password in KeyChain
|
||||||
job = new WritePasswordJob(Theme::instance()->appName());
|
|
||||||
job->setKey( key );
|
job->setKey( key );
|
||||||
job->setTextData(_passwd);
|
job->setTextData(_passwd);
|
||||||
|
|
||||||
@@ -338,9 +279,10 @@ void CredentialStore::saveCredentials( )
|
|||||||
_state = AsyncWriting;
|
_state = AsyncWriting;
|
||||||
job->start();
|
job->start();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CredentialStore::Settings:
|
case CredentialStore::Settings:
|
||||||
cfgFile.writePassword( _passwd );
|
cfgFile.setPassword( _passwd );
|
||||||
reset();
|
reset();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -369,10 +311,9 @@ void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job )
|
|||||||
} else {
|
} else {
|
||||||
qDebug() << "Successfully stored password for user " << _user;
|
qDebug() << "Successfully stored password for user " << _user;
|
||||||
// Try to remove password formerly stored in the config file.
|
// Try to remove password formerly stored in the config file.
|
||||||
MirallConfigFile cfgFile;
|
HttpConfigFile cfgFile;
|
||||||
cfgFile.clearPasswordFromConfig();
|
cfgFile.removePassword();
|
||||||
_state = NotFetched;
|
_state = NotFetched;
|
||||||
_tries = 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Error: KeyChain Write Password Job failed!";
|
qDebug() << "Error: KeyChain Write Password Job failed!";
|
||||||
@@ -34,10 +34,8 @@ namespace Mirall {
|
|||||||
* The fetchCredentials() call changes the internal state of the credential store
|
* The fetchCredentials() call changes the internal state of the credential store
|
||||||
* to one of
|
* to one of
|
||||||
* Ok: There are credentials. Note that it's unknown if they are correct!!
|
* Ok: There are credentials. Note that it's unknown if they are correct!!
|
||||||
* UserCanceled: The fetching involved user interaction and the user canceled
|
|
||||||
* the operation. No valid credentials are there.
|
|
||||||
* TooManyAttempts: The user tried to often to enter a password.
|
|
||||||
* Fetching: The fetching is not yet finished.
|
* Fetching: The fetching is not yet finished.
|
||||||
|
* EntryNotFound: No password entry found in the storage.
|
||||||
* Error: A general error happened.
|
* Error: A general error happened.
|
||||||
* After fetching has finished, signal fetchCredentialsFinished(bool) is emitted.
|
* After fetching has finished, signal fetchCredentialsFinished(bool) is emitted.
|
||||||
* The result can be retrieved with state() and password() and user() methods.
|
* The result can be retrieved with state() and password() and user() methods.
|
||||||
@@ -49,20 +47,16 @@ class CredentialStore : public QObject
|
|||||||
public:
|
public:
|
||||||
enum CredState { NotFetched = 0,
|
enum CredState { NotFetched = 0,
|
||||||
Ok,
|
Ok,
|
||||||
UserCanceled,
|
|
||||||
Fetching,
|
Fetching,
|
||||||
AsyncFetching,
|
AsyncFetching,
|
||||||
EntryNotFound,
|
EntryNotFound,
|
||||||
AccessDeniedByUser,
|
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
NoKeychainBackend,
|
NoKeychainBackend,
|
||||||
Error,
|
Error,
|
||||||
AsyncWriting,
|
AsyncWriting };
|
||||||
TooManyAttempts };
|
|
||||||
|
|
||||||
enum CredentialType {
|
enum CredentialType {
|
||||||
User = 0,
|
Settings = 0,
|
||||||
Settings,
|
|
||||||
KeyChain
|
KeyChain
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -97,19 +91,13 @@ public:
|
|||||||
* The function also sets the state to ok.
|
* The function also sets the state to ok.
|
||||||
* @param url - the connection url
|
* @param url - the connection url
|
||||||
* @param user - the user name
|
* @param user - the user name
|
||||||
* @param password - the password.
|
|
||||||
*/
|
*/
|
||||||
void setCredentials( const QString&, const QString&, const QString&, bool );
|
void setCredentials( const QString& url, const QString& user, const QString& pwd);
|
||||||
|
|
||||||
void saveCredentials( );
|
void saveCredentials( );
|
||||||
|
|
||||||
QString errorMessage();
|
QString errorMessage();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief canTryAgain - check if another try to get credentials makes sense.
|
|
||||||
*/
|
|
||||||
bool canTryAgain();
|
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
@@ -125,7 +113,6 @@ signals:
|
|||||||
protected slots:
|
protected slots:
|
||||||
void slotKeyChainReadFinished( QKeychain::Job* );
|
void slotKeyChainReadFinished( QKeychain::Job* );
|
||||||
void slotKeyChainWriteFinished( QKeychain::Job* );
|
void slotKeyChainWriteFinished( QKeychain::Job* );
|
||||||
void slotUserDialogDone(int);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit CredentialStore(QObject *parent = 0);
|
explicit CredentialStore(QObject *parent = 0);
|
||||||
@@ -138,9 +125,7 @@ private:
|
|||||||
static QString _user;
|
static QString _user;
|
||||||
static QString _url;
|
static QString _url;
|
||||||
static QString _errorMsg;
|
static QString _errorMsg;
|
||||||
static int _tries;
|
|
||||||
static CredentialType _type;
|
static CredentialType _type;
|
||||||
QInputDialog *_inputDialog;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
81
src/creds/http/httpconfigfile.cpp
Normal file
81
src/creds/http/httpconfigfile.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "creds/http/httpconfigfile.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const char userC[] = "user";
|
||||||
|
const char passwdC[] = "passwd";
|
||||||
|
const char oldPasswdC[] = "password";
|
||||||
|
|
||||||
|
} // ns
|
||||||
|
|
||||||
|
QString HttpConfigFile::user() const
|
||||||
|
{
|
||||||
|
return retrieveData(QString(), QLatin1String(userC)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConfigFile::setUser(const QString& user)
|
||||||
|
{
|
||||||
|
storeData(QString(), QLatin1String(userC), QVariant(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HttpConfigFile::password() const
|
||||||
|
{
|
||||||
|
const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC)));
|
||||||
|
|
||||||
|
if (passwd.isValid()) {
|
||||||
|
return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConfigFile::setPassword(const QString& password)
|
||||||
|
{
|
||||||
|
QByteArray pwdba = password.toUtf8();
|
||||||
|
storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) );
|
||||||
|
removeOldPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpConfigFile::passwordExists() const
|
||||||
|
{
|
||||||
|
return dataExists(QString(), QLatin1String(passwdC));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConfigFile::removePassword()
|
||||||
|
{
|
||||||
|
removeOldPassword();
|
||||||
|
removeData(QString(), QLatin1String(passwdC));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConfigFile::fixupOldPassword()
|
||||||
|
{
|
||||||
|
const QString old(QString::fromLatin1(oldPasswdC));
|
||||||
|
|
||||||
|
if (dataExists(QString(), old)) {
|
||||||
|
setPassword(retrieveData(QString(), old).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConfigFile::removeOldPassword()
|
||||||
|
{
|
||||||
|
removeData(QString(), QLatin1String(oldPasswdC));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
40
src/creds/http/httpconfigfile.h
Normal file
40
src/creds/http/httpconfigfile.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
||||||
|
#define MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
||||||
|
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class HttpConfigFile : public MirallConfigFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString user() const;
|
||||||
|
void setUser(const QString& user);
|
||||||
|
|
||||||
|
QString password() const;
|
||||||
|
void setPassword(const QString& password);
|
||||||
|
bool passwordExists() const;
|
||||||
|
void removePassword();
|
||||||
|
void fixupOldPassword();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void removeOldPassword();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
218
src/creds/httpcredentials.cpp
Normal file
218
src/creds/httpcredentials.cpp
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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 <QMutex>
|
||||||
|
|
||||||
|
#include "creds/httpcredentials.h"
|
||||||
|
#include "mirall/owncloudinfo.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "creds/http/credentialstore.h"
|
||||||
|
#include "creds/credentialscommon.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
int getauth(const char *prompt,
|
||||||
|
char *buf,
|
||||||
|
size_t len,
|
||||||
|
int echo,
|
||||||
|
int verify,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
int re = 0;
|
||||||
|
QMutex mutex;
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
HttpCredentials* http_credentials = dynamic_cast< HttpCredentials* > (cfg.getCredentials());
|
||||||
|
|
||||||
|
if (!http_credentials) {
|
||||||
|
qDebug() << "Not a HTTP creds instance!";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
|
||||||
|
QString user = http_credentials->user();
|
||||||
|
QString pwd = http_credentials->password();
|
||||||
|
|
||||||
|
if( qPrompt == QLatin1String("Enter your username:") ) {
|
||||||
|
// qDebug() << "OOO Username requested!";
|
||||||
|
QMutexLocker locker( &mutex );
|
||||||
|
qstrncpy( buf, user.toUtf8().constData(), len );
|
||||||
|
} else if( qPrompt == QLatin1String("Enter your password:") ) {
|
||||||
|
QMutexLocker locker( &mutex );
|
||||||
|
// qDebug() << "OOO Password requested!";
|
||||||
|
qstrncpy( buf, pwd.toUtf8().constData(), len );
|
||||||
|
} else {
|
||||||
|
re = handleNeonSSLProblems(prompt, buf, len, echo, verify, userdata);
|
||||||
|
}
|
||||||
|
return re;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns
|
||||||
|
|
||||||
|
HttpCredentials::HttpCredentials()
|
||||||
|
: _user(),
|
||||||
|
_password(),
|
||||||
|
_ready(false),
|
||||||
|
_attempts()
|
||||||
|
{}
|
||||||
|
|
||||||
|
HttpCredentials::HttpCredentials(const QString& user, const QString& password)
|
||||||
|
: _user(user),
|
||||||
|
_password(password),
|
||||||
|
_ready(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void HttpCredentials::syncContextPreInit (CSYNC* ctx)
|
||||||
|
{
|
||||||
|
csync_set_auth_callback (ctx, getauth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::syncContextPreStart (CSYNC* ctx)
|
||||||
|
{
|
||||||
|
// TODO: This should not be a part of this method, but we don't have
|
||||||
|
// any way to get "session_key" module property from csync. Had we
|
||||||
|
// have it, then we could remove this code and keep it in
|
||||||
|
// csyncthread code (or folder code, git remembers).
|
||||||
|
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
|
||||||
|
QString cookiesAsString;
|
||||||
|
|
||||||
|
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
|
||||||
|
// when https://github.com/owncloud/core/pull/4042 is merged.
|
||||||
|
foreach(QNetworkCookie c, cookies) {
|
||||||
|
cookiesAsString += c.name();
|
||||||
|
cookiesAsString += '=';
|
||||||
|
cookiesAsString += c.value();
|
||||||
|
cookiesAsString += "; ";
|
||||||
|
}
|
||||||
|
|
||||||
|
csync_set_module_property(ctx, "session_key", cookiesAsString.toLatin1().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpCredentials::changed(AbstractCredentials* credentials) const
|
||||||
|
{
|
||||||
|
HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials));
|
||||||
|
|
||||||
|
if (!other || other->user() != this->user()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HttpCredentials::authType() const
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("http");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HttpCredentials::user() const
|
||||||
|
{
|
||||||
|
return _user;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HttpCredentials::password() const
|
||||||
|
{
|
||||||
|
return _password;
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager* HttpCredentials::getQNAM() const
|
||||||
|
{
|
||||||
|
MirallAccessManager* qnam = new MirallAccessManager;
|
||||||
|
|
||||||
|
connect( qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
|
||||||
|
this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*)));
|
||||||
|
|
||||||
|
return qnam;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpCredentials::ready() const
|
||||||
|
{
|
||||||
|
return _ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::fetch()
|
||||||
|
{
|
||||||
|
if (_ready) {
|
||||||
|
Q_EMIT fetched();
|
||||||
|
} else {
|
||||||
|
// TODO: merge CredentialStore into HttpCredentials?
|
||||||
|
CredentialStore* store(CredentialStore::instance());
|
||||||
|
connect(store, SIGNAL(fetchCredentialsFinished(bool)),
|
||||||
|
this, SLOT(slotCredentialsFetched(bool)));
|
||||||
|
store->fetchCredentials();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::persistForUrl(const QString& url)
|
||||||
|
{
|
||||||
|
CredentialStore* store(CredentialStore::instance());
|
||||||
|
store->setCredentials(url, _user, _password);
|
||||||
|
store->saveCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::slotCredentialsFetched(bool ok)
|
||||||
|
{
|
||||||
|
_ready = ok;
|
||||||
|
if (_ready) {
|
||||||
|
CredentialStore* store(CredentialStore::instance());
|
||||||
|
_user = store->user();
|
||||||
|
_password = store->password();
|
||||||
|
}
|
||||||
|
Q_EMIT fetched();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)
|
||||||
|
{
|
||||||
|
if( !(authenticator && reply) ) return;
|
||||||
|
|
||||||
|
qDebug() << "Authenticating request for " << reply->url();
|
||||||
|
|
||||||
|
if (_attempts.contains(reply)) {
|
||||||
|
++_attempts[reply];
|
||||||
|
} else {
|
||||||
|
connect(reply, SIGNAL(finished()),
|
||||||
|
this, SLOT(slotReplyFinished()));
|
||||||
|
_attempts[reply] = 1;
|
||||||
|
}
|
||||||
|
// TODO: Replace it with something meaningful...
|
||||||
|
//if( reply->url().toString().startsWith( webdavUrl( _connection ) ) ) {
|
||||||
|
if (_attempts[reply] > 1) {
|
||||||
|
qDebug() << "Too many attempts to authenticate. Stop request.";
|
||||||
|
reply->close();
|
||||||
|
} else {
|
||||||
|
authenticator->setUser( _user );
|
||||||
|
authenticator->setPassword( _password );
|
||||||
|
}
|
||||||
|
//} else {
|
||||||
|
// qDebug() << "WRN: attempt to authenticate to different url - closing.";
|
||||||
|
// reply->close();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpCredentials::slotReplyFinished()
|
||||||
|
{
|
||||||
|
QNetworkReply* reply = qobject_cast< QNetworkReply* >(sender());
|
||||||
|
|
||||||
|
disconnect(reply, SIGNAL(finished()),
|
||||||
|
this, SLOT(slotReplyFinished()));
|
||||||
|
_attempts.remove (reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
64
src/creds/httpcredentials.h
Normal file
64
src/creds/httpcredentials.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_HTTP_CREDENTIALS_H
|
||||||
|
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
|
class QNetworkReply;
|
||||||
|
class QAuthenticator;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class HttpCredentials : public AbstractCredentials
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
HttpCredentials();
|
||||||
|
HttpCredentials(const QString& user, const QString& password);
|
||||||
|
|
||||||
|
void syncContextPreInit(CSYNC* ctx);
|
||||||
|
void syncContextPreStart(CSYNC* ctx);
|
||||||
|
bool changed(AbstractCredentials* credentials) const;
|
||||||
|
QString authType() const;
|
||||||
|
QNetworkAccessManager* getQNAM() const;
|
||||||
|
bool ready() const;
|
||||||
|
void fetch();
|
||||||
|
void persistForUrl(const QString& url);
|
||||||
|
|
||||||
|
QString user() const;
|
||||||
|
QString password() const;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void slotCredentialsFetched(bool);
|
||||||
|
void slotAuthentication(QNetworkReply*, QAuthenticator*);
|
||||||
|
void slotReplyFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _user;
|
||||||
|
QString _password;
|
||||||
|
bool _ready;
|
||||||
|
QMap<QNetworkReply*, int> _attempts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
55
src/creds/shibboleth/shibbolethaccessmanager.cpp
Normal file
55
src/creds/shibboleth/shibbolethaccessmanager.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
|
#include "creds/shibboleth/shibbolethaccessmanager.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
ShibbolethAccessManager::ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent)
|
||||||
|
: MirallAccessManager (parent),
|
||||||
|
_cookie(cookie)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
|
||||||
|
{
|
||||||
|
if (!_cookie.name().isEmpty()) {
|
||||||
|
QNetworkCookieJar* jar(cookieJar());
|
||||||
|
QUrl url(request.url());
|
||||||
|
QList<QNetworkCookie> cookies;
|
||||||
|
|
||||||
|
Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) {
|
||||||
|
if (!cookie.name().startsWith("_shibsession_")) {
|
||||||
|
cookies << cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cookies << _cookie;
|
||||||
|
jar->setCookiesFromUrl(cookies, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Creating a request to " << request.url().toString() << " with shibboleth cookie:" << _cookie.name();
|
||||||
|
|
||||||
|
return MirallAccessManager::createRequest (op, request, outgoingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethAccessManager::setCookie(const QNetworkCookie& cookie)
|
||||||
|
{
|
||||||
|
qDebug() << "Got new shibboleth cookie:" << cookie.name();
|
||||||
|
_cookie = cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
43
src/creds/shibboleth/shibbolethaccessmanager.h
Normal file
43
src/creds/shibboleth/shibbolethaccessmanager.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
|
||||||
|
#define MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
|
||||||
|
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethAccessManager : public MirallAccessManager
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent = 0);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setCookie(const QNetworkCookie& cookie);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QNetworkCookie _cookie;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
104
src/creds/shibboleth/shibbolethconfigfile.cpp
Normal file
104
src/creds/shibboleth/shibbolethconfigfile.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "creds/shibboleth/shibbolethconfigfile.h"
|
||||||
|
#include "creds/shibboleth/shibbolethcookiejar.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const char otherCookiesC[] = "otherCookies";
|
||||||
|
|
||||||
|
} // ns
|
||||||
|
|
||||||
|
void ShibbolethConfigFile::storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookiesForUrl)
|
||||||
|
{
|
||||||
|
if (cookiesForUrl.isEmpty()) {
|
||||||
|
removeData(QString(), QString::fromLatin1(otherCookiesC));
|
||||||
|
} else {
|
||||||
|
QByteArray data;
|
||||||
|
QTextStream stream(&data);
|
||||||
|
|
||||||
|
Q_FOREACH (const QUrl& url, cookiesForUrl.keys()) {
|
||||||
|
const QList<QNetworkCookie>& cookies(cookiesForUrl[url]);
|
||||||
|
|
||||||
|
if (cookies.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stream << "URL: " << url.toString().toUtf8() << "\n";
|
||||||
|
qDebug() << "URL: " << url.toString().toUtf8();
|
||||||
|
|
||||||
|
Q_FOREACH (const QNetworkCookie& cookie, cookies) {
|
||||||
|
stream << cookie.toRawForm(QNetworkCookie::NameAndValueOnly) << "\n";
|
||||||
|
qDebug() << cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.flush();
|
||||||
|
|
||||||
|
const QByteArray encodedCookies(data.toBase64());
|
||||||
|
|
||||||
|
qDebug() << "Raw cookies:\n" << data;
|
||||||
|
qDebug() << "Encoded cookies: " << encodedCookies;
|
||||||
|
|
||||||
|
storeData(QString(), QString::fromLatin1(otherCookiesC), QVariant(encodedCookies));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShibbolethCookieJar* ShibbolethConfigFile::createCookieJar() const
|
||||||
|
{
|
||||||
|
ShibbolethCookieJar* jar = new ShibbolethCookieJar();
|
||||||
|
const QVariant variant(retrieveData(QString(), QString::fromLatin1(otherCookiesC)));
|
||||||
|
|
||||||
|
if (variant.isValid()) {
|
||||||
|
QByteArray data(QByteArray::fromBase64(variant.toByteArray()));
|
||||||
|
QTextStream stream (&data);
|
||||||
|
const QString urlHeader(QString::fromLatin1("URL: "));
|
||||||
|
QUrl currentUrl;
|
||||||
|
QList<QNetworkCookie> currentCookies;
|
||||||
|
|
||||||
|
qDebug() << "Got valid cookies variant: " << data;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
const QString line(stream.readLine());
|
||||||
|
|
||||||
|
qDebug() << line;
|
||||||
|
|
||||||
|
if (line.startsWith(urlHeader)) {
|
||||||
|
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
|
||||||
|
jar->setCookiesFromUrl(currentCookies, currentUrl);
|
||||||
|
currentCookies.clear();
|
||||||
|
currentUrl.clear();
|
||||||
|
}
|
||||||
|
currentUrl = QUrl(line.mid(5));
|
||||||
|
} else if (!currentUrl.isEmpty()) {
|
||||||
|
const int equalPos(line.indexOf('='));
|
||||||
|
|
||||||
|
currentCookies << QNetworkCookie(line.left(equalPos).toUtf8(), line.mid(equalPos + 1).toUtf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
|
||||||
|
jar->setCookiesFromUrl(currentCookies, currentUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jar;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
38
src/creds/shibboleth/shibbolethconfigfile.h
Normal file
38
src/creds/shibboleth/shibbolethconfigfile.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
|
||||||
|
#define MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethCookieJar;
|
||||||
|
|
||||||
|
class ShibbolethConfigFile : public MirallConfigFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookies);
|
||||||
|
ShibbolethCookieJar* createCookieJar() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
34
src/creds/shibboleth/shibbolethcookiejar.cpp
Normal file
34
src/creds/shibboleth/shibbolethcookiejar.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "creds/shibboleth/shibbolethcookiejar.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
ShibbolethCookieJar::ShibbolethCookieJar (QObject* parent)
|
||||||
|
: QNetworkCookieJar (parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool ShibbolethCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
||||||
|
{
|
||||||
|
if (QNetworkCookieJar::setCookiesFromUrl (cookieList, url)) {
|
||||||
|
Q_EMIT newCookiesForUrl (cookieList, url);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
41
src/creds/shibboleth/shibbolethcookiejar.h
Normal file
41
src/creds/shibboleth/shibbolethcookiejar.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
|
||||||
|
#define MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
|
||||||
|
|
||||||
|
#include <QNetworkCookieJar>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
class QUrl;
|
||||||
|
class QNetworkCookie;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethCookieJar : public QNetworkCookieJar
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShibbolethCookieJar (QObject* parent = 0);
|
||||||
|
|
||||||
|
virtual bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void newCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
52
src/creds/shibboleth/shibbolethrefresher.cpp
Normal file
52
src/creds/shibboleth/shibbolethrefresher.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QEventLoop>
|
||||||
|
|
||||||
|
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||||
|
#include "creds/shibbolethcredentials.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
ShibbolethRefresher::ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
|
||||||
|
: QObject(parent),
|
||||||
|
_creds(creds),
|
||||||
|
_csync_ctx(csync_ctx)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ShibbolethRefresher::refresh()
|
||||||
|
{
|
||||||
|
QEventLoop loop;
|
||||||
|
|
||||||
|
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||||
|
this, SLOT(onInvalidatedAndFetched(QByteArray)));
|
||||||
|
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||||
|
&loop, SLOT(quit()));
|
||||||
|
QMetaObject::invokeMethod(_creds, "invalidateAndFetch", Qt::QueuedConnection);
|
||||||
|
loop.exec();
|
||||||
|
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||||
|
&loop, SLOT(quit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
|
||||||
|
{
|
||||||
|
// "cookies" is const and its data() return const void*. We want just void*.
|
||||||
|
QByteArray myCookies(cookies);
|
||||||
|
|
||||||
|
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||||
|
this, SLOT(onInvalidatedAndFetched(QByteArray)));
|
||||||
|
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
47
src/creds/shibboleth/shibbolethrefresher.h
Normal file
47
src/creds/shibboleth/shibbolethrefresher.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
|
||||||
|
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <csync.h>
|
||||||
|
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethCredentials;
|
||||||
|
|
||||||
|
class ShibbolethRefresher : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
|
||||||
|
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onInvalidatedAndFetched(const QByteArray& cookieData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ShibbolethCredentials* _creds;
|
||||||
|
CSYNC* _csync_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
104
src/creds/shibboleth/shibbolethwebview.cpp
Normal file
104
src/creds/shibboleth/shibbolethwebview.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
#include <QWebFrame>
|
||||||
|
#include <QWebPage>
|
||||||
|
|
||||||
|
#include "creds/shibboleth/shibbolethcookiejar.h"
|
||||||
|
#include "creds/shibboleth/shibbolethwebview.h"
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
void ShibbolethWebView::setup(const QUrl& url, ShibbolethCookieJar* jar)
|
||||||
|
{
|
||||||
|
MirallAccessManager* nm = new MirallAccessManager(this);
|
||||||
|
QWebPage* page = new QWebPage(this);
|
||||||
|
|
||||||
|
jar->setParent(this);
|
||||||
|
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
|
||||||
|
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
|
||||||
|
connect(page, SIGNAL(loadStarted()),
|
||||||
|
this, SLOT(slotLoadStarted()));
|
||||||
|
connect(page, SIGNAL(loadFinished(bool)),
|
||||||
|
this, SLOT(slotLoadFinished()));
|
||||||
|
|
||||||
|
nm->setCookieJar(jar);
|
||||||
|
page->setNetworkAccessManager(nm);
|
||||||
|
page->mainFrame ()->load (url);
|
||||||
|
this->setPage (page);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShibbolethWebView::ShibbolethWebView(const QUrl& url, QWidget* parent)
|
||||||
|
: QWebView(parent)
|
||||||
|
{
|
||||||
|
setup(url, new ShibbolethCookieJar(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
ShibbolethWebView::~ShibbolethWebView()
|
||||||
|
{
|
||||||
|
slotLoadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShibbolethWebView::ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent)
|
||||||
|
: QWebView(parent)
|
||||||
|
{
|
||||||
|
setup(url, jar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
||||||
|
{
|
||||||
|
QList<QNetworkCookie> otherCookies;
|
||||||
|
QNetworkCookie shibCookie;
|
||||||
|
|
||||||
|
Q_FOREACH (const QNetworkCookie& cookie, cookieList) {
|
||||||
|
if (cookie.name().startsWith ("_shibsession_")) {
|
||||||
|
if (shibCookie.name().isEmpty()) {
|
||||||
|
shibCookie = cookie;
|
||||||
|
} else {
|
||||||
|
qWarning() << "Too many Shibboleth session cookies at once!";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otherCookies << cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!otherCookies.isEmpty()) {
|
||||||
|
Q_EMIT otherCookiesReceived(otherCookies, url);
|
||||||
|
}
|
||||||
|
if (!shibCookie.name().isEmpty()) {
|
||||||
|
Q_EMIT shibbolethCookieReceived(shibCookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethWebView::hideEvent(QHideEvent* event)
|
||||||
|
{
|
||||||
|
Q_EMIT viewHidden();
|
||||||
|
QWebView::hideEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethWebView::slotLoadStarted()
|
||||||
|
{
|
||||||
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethWebView::slotLoadFinished()
|
||||||
|
{
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
56
src/creds/shibboleth/shibbolethwebview.h
Normal file
56
src/creds/shibboleth/shibbolethwebview.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
|
||||||
|
#define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QWebView>
|
||||||
|
|
||||||
|
class QNetworkCookie;
|
||||||
|
class QUrl;
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethCookieJar;
|
||||||
|
|
||||||
|
class ShibbolethWebView : public QWebView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShibbolethWebView(const QUrl& url, QWidget* parent = 0);
|
||||||
|
ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent = 0);
|
||||||
|
~ShibbolethWebView();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void hideEvent(QHideEvent* event);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void shibbolethCookieReceived(const QNetworkCookie& cookie);
|
||||||
|
void viewHidden();
|
||||||
|
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
|
void slotLoadStarted();
|
||||||
|
void slotLoadFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setup(const QUrl& url, ShibbolethCookieJar* jar);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
231
src/creds/shibbolethcredentials.cpp
Normal file
231
src/creds/shibbolethcredentials.cpp
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "creds/shibbolethcredentials.h"
|
||||||
|
#include "creds/shibboleth/shibbolethaccessmanager.h"
|
||||||
|
#include "creds/shibboleth/shibbolethwebview.h"
|
||||||
|
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||||
|
#include "creds/shibboleth/shibbolethconfigfile.h"
|
||||||
|
#include "creds/credentialscommon.h"
|
||||||
|
#include "mirall/owncloudinfo.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
int shibboleth_redirect_callback(CSYNC* csync_ctx,
|
||||||
|
const char* uri)
|
||||||
|
{
|
||||||
|
if (!csync_ctx || !uri) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString qurl(QString::fromLatin1(uri));
|
||||||
|
QRegExp shibbolethyWords ("SAML|wayf");
|
||||||
|
|
||||||
|
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
|
||||||
|
if (!qurl.contains(shibbolethyWords)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutex mutex;
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
ShibbolethCredentials* creds = dynamic_cast< ShibbolethCredentials* > (cfg.getCredentials());
|
||||||
|
|
||||||
|
if (!creds) {
|
||||||
|
qDebug() << "Not a Shibboleth creds instance!";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShibbolethRefresher refresher(creds, csync_ctx);
|
||||||
|
|
||||||
|
// blocks
|
||||||
|
refresher.refresh();
|
||||||
|
|
||||||
|
return creds->ready() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns
|
||||||
|
|
||||||
|
ShibbolethCredentials::ShibbolethCredentials()
|
||||||
|
: _shibCookie(),
|
||||||
|
_ready(false),
|
||||||
|
_browser(0),
|
||||||
|
_otherCookies()
|
||||||
|
{}
|
||||||
|
|
||||||
|
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
|
||||||
|
: _shibCookie(cookie),
|
||||||
|
_ready(true),
|
||||||
|
_browser(0),
|
||||||
|
_otherCookies(otherCookies)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
|
||||||
|
{
|
||||||
|
csync_set_auth_callback (ctx, handleNeonSSLProblems);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ShibbolethCredentials::prepareCookieData() const
|
||||||
|
{
|
||||||
|
QString cookiesAsString;
|
||||||
|
// TODO: This should not be a part of this method, but we don't
|
||||||
|
// have any way to get "session_key" module property from
|
||||||
|
// csync. Had we have it, then we could just append shibboleth
|
||||||
|
// cookies to the "session_key" value and set it in csync module.
|
||||||
|
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
|
||||||
|
QMap<QString, QString> uniqueCookies;
|
||||||
|
|
||||||
|
cookies << _shibCookie;
|
||||||
|
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
|
||||||
|
// when https://github.com/owncloud/core/pull/4042 is merged.
|
||||||
|
foreach(QNetworkCookie c, cookies) {
|
||||||
|
const QString cookieName(c.name());
|
||||||
|
|
||||||
|
if (cookieName.startsWith("_shibsession_")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uniqueCookies.insert(cookieName, c.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_shibCookie.name().isEmpty()) {
|
||||||
|
uniqueCookies.insert(_shibCookie.name(), _shibCookie.value());
|
||||||
|
}
|
||||||
|
foreach(const QString& cookieName, uniqueCookies.keys()) {
|
||||||
|
cookiesAsString += cookieName;
|
||||||
|
cookiesAsString += '=';
|
||||||
|
cookiesAsString += uniqueCookies[cookieName];
|
||||||
|
cookiesAsString += "; ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return cookiesAsString.toLatin1();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
|
||||||
|
{
|
||||||
|
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
|
||||||
|
|
||||||
|
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
|
||||||
|
|
||||||
|
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
|
||||||
|
csync_set_module_property(ctx, "redirect_callback", &cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
|
||||||
|
{
|
||||||
|
ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials));
|
||||||
|
|
||||||
|
if (!other || other->cookie() != this->cookie()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ShibbolethCredentials::authType() const
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("shibboleth");
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkCookie ShibbolethCredentials::cookie() const
|
||||||
|
{
|
||||||
|
return _shibCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
|
||||||
|
{
|
||||||
|
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(newCookie(QNetworkCookie)),
|
||||||
|
qnam, SLOT(setCookie(QNetworkCookie)));
|
||||||
|
return qnam;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShibbolethCredentials::ready() const
|
||||||
|
{
|
||||||
|
return _ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::fetch()
|
||||||
|
{
|
||||||
|
if (_ready) {
|
||||||
|
Q_EMIT fetched();
|
||||||
|
} else {
|
||||||
|
ShibbolethConfigFile cfg;
|
||||||
|
|
||||||
|
_browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl()), cfg.createCookieJar());
|
||||||
|
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
|
||||||
|
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
|
||||||
|
connect(_browser, SIGNAL(viewHidden()),
|
||||||
|
this, SLOT(slotBrowserHidden()));
|
||||||
|
_browser->show ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::persistForUrl(const QString& /*url*/)
|
||||||
|
{
|
||||||
|
ShibbolethConfigFile cfg;
|
||||||
|
|
||||||
|
cfg.storeCookies(_otherCookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::disposeBrowser()
|
||||||
|
{
|
||||||
|
disconnect(_browser, SIGNAL(viewHidden()),
|
||||||
|
this, SLOT(slotBrowserHidden()));
|
||||||
|
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
|
||||||
|
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
|
||||||
|
_browser->hide();
|
||||||
|
_browser->deleteLater();
|
||||||
|
_browser = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie)
|
||||||
|
{
|
||||||
|
disposeBrowser();
|
||||||
|
_ready = true;
|
||||||
|
_shibCookie = cookie;
|
||||||
|
Q_EMIT newCookie(_shibCookie);
|
||||||
|
Q_EMIT fetched();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::slotBrowserHidden()
|
||||||
|
{
|
||||||
|
disposeBrowser();
|
||||||
|
_ready = false;
|
||||||
|
_shibCookie = QNetworkCookie();
|
||||||
|
Q_EMIT fetched();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::invalidateAndFetch()
|
||||||
|
{
|
||||||
|
_ready = false;
|
||||||
|
connect (this, SIGNAL(fetched()),
|
||||||
|
this, SLOT(onFetched()));
|
||||||
|
fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShibbolethCredentials::onFetched()
|
||||||
|
{
|
||||||
|
disconnect (this, SIGNAL(fetched()),
|
||||||
|
this, SLOT(onFetched()));
|
||||||
|
|
||||||
|
Q_EMIT invalidatedAndFetched(prepareCookieData());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
72
src/creds/shibbolethcredentials.h
Normal file
72
src/creds/shibbolethcredentials.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
|
||||||
|
#define MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShibbolethWebView;
|
||||||
|
|
||||||
|
class ShibbolethCredentials : public AbstractCredentials
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShibbolethCredentials();
|
||||||
|
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
|
||||||
|
|
||||||
|
void syncContextPreInit(CSYNC* ctx);
|
||||||
|
void syncContextPreStart(CSYNC* ctx);
|
||||||
|
bool changed(AbstractCredentials* credentials) const;
|
||||||
|
QString authType() const;
|
||||||
|
QNetworkAccessManager* getQNAM() const;
|
||||||
|
bool ready() const;
|
||||||
|
void fetch();
|
||||||
|
void persistForUrl(const QString& url);
|
||||||
|
|
||||||
|
QNetworkCookie cookie() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void invalidateAndFetch();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onShibbolethCookieReceived(const QNetworkCookie& cookie);
|
||||||
|
void slotBrowserHidden();
|
||||||
|
void onFetched();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void newCookie(const QNetworkCookie& cookie);
|
||||||
|
void invalidatedAndFetched(const QByteArray& cookieData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray prepareCookieData() const;
|
||||||
|
void disposeBrowser();
|
||||||
|
|
||||||
|
QNetworkCookie _shibCookie;
|
||||||
|
bool _ready;
|
||||||
|
ShibbolethWebView* _browser;
|
||||||
|
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
24
src/main.cpp
24
src/main.cpp
@@ -13,6 +13,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mirall/application.h"
|
#include "mirall/application.h"
|
||||||
|
#include "mirall/theme.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -20,7 +23,12 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
Mirall::Application app(argc, argv);
|
Mirall::Application app(argc, argv);
|
||||||
app.initialize();
|
app.initialize();
|
||||||
|
|
||||||
|
if( app.giveHelp() ) {
|
||||||
|
app.showHelp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// if the application is already running, notify it.
|
// if the application is already running, notify it.
|
||||||
if( app.isRunning() ) {
|
if( app.isRunning() ) {
|
||||||
QStringList args = app.arguments();
|
QStringList args = app.arguments();
|
||||||
@@ -30,12 +38,16 @@ int main(int argc, char **argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
// if help requested, show on command line and exit.
|
|
||||||
if( ! app.giveHelp() ) {
|
|
||||||
return app.exec();
|
|
||||||
} else {
|
} else {
|
||||||
app.showHelp();
|
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||||
|
QMessageBox::critical(0, qApp->translate("main.cpp", "System Tray not available"),
|
||||||
|
qApp->translate("main.cpp", "%1 requires on a working system tray. "
|
||||||
|
"If you are running XFCE, please follow "
|
||||||
|
"<a href=\"http://docs.xfce.org/xfce/xfce4-panel/systray\">these instructions</a>. "
|
||||||
|
"Otherwise, please install a system tray application such as 'trayer' and try again.")
|
||||||
|
.arg(Mirall::Theme::instance()->appNameGUI()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
679
src/mirall/accountsettings.cpp
Normal file
679
src/mirall/accountsettings.cpp
Normal file
@@ -0,0 +1,679 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "accountsettings.h"
|
||||||
|
#include "ui_accountsettings.h"
|
||||||
|
|
||||||
|
#include "mirall/theme.h"
|
||||||
|
#include "mirall/folderman.h"
|
||||||
|
#include "mirall/owncloudinfo.h"
|
||||||
|
#include "mirall/folderwizard.h"
|
||||||
|
#include "mirall/folderstatusmodel.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/application.h"
|
||||||
|
#include "mirall/owncloudsetupwizard.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
#include "mirall/ignorelisteditor.h"
|
||||||
|
#include "mirall/itemprogressdialog.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QKeySequence>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
AccountSettings::AccountSettings(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::AccountSettings),
|
||||||
|
_item(0)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
_model = new FolderStatusModel;
|
||||||
|
_model->setParent(this);
|
||||||
|
FolderStatusDelegate *delegate = new FolderStatusDelegate;
|
||||||
|
|
||||||
|
ui->_folderList->setItemDelegate( delegate );
|
||||||
|
ui->_folderList->setModel( _model );
|
||||||
|
ui->_folderList->setMinimumWidth( 300 );
|
||||||
|
ui->_folderList->setEditTriggers( QAbstractItemView::NoEditTriggers );
|
||||||
|
|
||||||
|
ui->_ButtonRemove->setEnabled(false);
|
||||||
|
ui->_ButtonEnable->setEnabled(false);
|
||||||
|
ui->_ButtonInfo->setEnabled(false);
|
||||||
|
ui->_ButtonAdd->setEnabled(true);
|
||||||
|
|
||||||
|
QAction *resetFolderAction = new QAction(this);
|
||||||
|
resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5));
|
||||||
|
connect(resetFolderAction, SIGNAL(triggered()), SLOT(slotResetCurrentFolder()));
|
||||||
|
addAction(resetFolderAction);
|
||||||
|
|
||||||
|
connect(ui->_ButtonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveCurrentFolder()));
|
||||||
|
connect(ui->_ButtonEnable, SIGNAL(clicked()), this, SLOT(slotEnableCurrentFolder()));
|
||||||
|
connect(ui->_ButtonInfo, SIGNAL(clicked()), this, SLOT(slotInfoAboutCurrentFolder()));
|
||||||
|
connect(ui->_ButtonAdd, SIGNAL(clicked()), this, SLOT(slotAddFolder()));
|
||||||
|
connect(ui->modifyAccountButton, SIGNAL(clicked()), SLOT(slotOpenAccountWizard()));
|
||||||
|
connect(ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));;
|
||||||
|
|
||||||
|
connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex)));
|
||||||
|
connect(ui->_folderList, SIGNAL(doubleClicked(QModelIndex)),SLOT(slotDoubleClicked(QModelIndex)));
|
||||||
|
|
||||||
|
ownCloudInfo *ocInfo = ownCloudInfo::instance();
|
||||||
|
slotUpdateQuota(ocInfo->lastQuotaTotalBytes(), ocInfo->lastQuotaUsedBytes());
|
||||||
|
connect(ocInfo, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotUpdateQuota(qint64,qint64)));
|
||||||
|
|
||||||
|
ui->connectLabel->setWordWrap( true );
|
||||||
|
|
||||||
|
setFolderList(FolderMan::instance()->map());
|
||||||
|
|
||||||
|
slotCheckConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
|
||||||
|
{
|
||||||
|
bool state = indx.isValid();
|
||||||
|
|
||||||
|
ui->_ButtonRemove->setEnabled( state );
|
||||||
|
ui->_ButtonEnable->setEnabled( state );
|
||||||
|
ui->_ButtonInfo->setEnabled( state );
|
||||||
|
|
||||||
|
if ( state ) {
|
||||||
|
bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
|
||||||
|
qDebug() << "folder is sync enabled: " << folderEnabled;
|
||||||
|
if ( folderEnabled ) {
|
||||||
|
ui->_ButtonEnable->setText( tr( "Pause" ) );
|
||||||
|
} else {
|
||||||
|
ui->_ButtonEnable->setText( tr( "Resume" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AccountSettings::slotAddFolder()
|
||||||
|
{
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
folderMan->setSyncEnabled(false); // do not start more syncs.
|
||||||
|
|
||||||
|
FolderWizard *folderWizard = new FolderWizard(this);
|
||||||
|
Folder::Map folderMap = folderMan->map();
|
||||||
|
folderWizard->setFolderMap( folderMap );
|
||||||
|
|
||||||
|
connect(folderWizard, SIGNAL(accepted()), SLOT(slotFolderWizardAccepted()));
|
||||||
|
connect(folderWizard, SIGNAL(rejected()), SLOT(slotFolderWizardRejected()));
|
||||||
|
folderWizard->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AccountSettings::slotFolderWizardAccepted()
|
||||||
|
{
|
||||||
|
FolderWizard *folderWizard = qobject_cast<FolderWizard*>(sender());
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
|
||||||
|
qDebug() << "* Folder wizard completed";
|
||||||
|
|
||||||
|
QString alias = folderWizard->field(QLatin1String("alias")).toString();
|
||||||
|
QString sourceFolder = folderWizard->field(QLatin1String("sourceFolder")).toString();
|
||||||
|
QString targetPath = folderWizard->property("targetPath").toString();
|
||||||
|
|
||||||
|
if (!FolderMan::ensureJournalGone( sourceFolder ))
|
||||||
|
return;
|
||||||
|
folderMan->addFolderDefinition(alias, sourceFolder, targetPath );
|
||||||
|
Folder *f = folderMan->setupFolderFromConfigFile( alias );
|
||||||
|
slotAddFolder( f );
|
||||||
|
folderMan->setSyncEnabled(true);
|
||||||
|
if( f ) {
|
||||||
|
folderMan->slotScheduleAllFolders();
|
||||||
|
emit folderChanged();
|
||||||
|
}
|
||||||
|
buttonsSetEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotFolderWizardRejected()
|
||||||
|
{
|
||||||
|
qDebug() << "* Folder wizard cancelled";
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
folderMan->setSyncEnabled(true);
|
||||||
|
folderMan->slotScheduleAllFolders();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotOpenAccountWizard()
|
||||||
|
{
|
||||||
|
this->topLevelWidget()->close();
|
||||||
|
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotAddFolder( Folder *folder )
|
||||||
|
{
|
||||||
|
if( ! folder || folder->alias().isEmpty() ) return;
|
||||||
|
|
||||||
|
QStandardItem *item = new QStandardItem();
|
||||||
|
folderToModelItem( item, folder );
|
||||||
|
_model->appendRow( item );
|
||||||
|
slotCheckConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AccountSettings::buttonsSetEnabled()
|
||||||
|
{
|
||||||
|
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
|
||||||
|
|
||||||
|
ui->_ButtonRemove->setEnabled(false);
|
||||||
|
if( Theme::instance()->singleSyncFolder() ) {
|
||||||
|
// only one folder synced folder allowed.
|
||||||
|
ui->_ButtonAdd->setVisible(!haveFolders);
|
||||||
|
} else {
|
||||||
|
ui->_ButtonAdd->setVisible(true);
|
||||||
|
ui->_ButtonAdd->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex selected = ui->_folderList->currentIndex();
|
||||||
|
bool isSelected = selected.isValid();
|
||||||
|
|
||||||
|
ui->_ButtonEnable->setEnabled(isSelected);
|
||||||
|
ui->_ButtonRemove->setEnabled(isSelected);
|
||||||
|
ui->_ButtonInfo->setEnabled(isSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::setListWidgetItem( QListWidgetItem *item )
|
||||||
|
{
|
||||||
|
_item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
|
||||||
|
{
|
||||||
|
if( ! item || !f ) return;
|
||||||
|
|
||||||
|
item->setData( f->nativePath(), FolderStatusDelegate::FolderPathRole );
|
||||||
|
item->setData( f->secondPath(), FolderStatusDelegate::FolderSecondPathRole );
|
||||||
|
item->setData( f->alias(), FolderStatusDelegate::FolderAliasRole );
|
||||||
|
item->setData( f->syncEnabled(), FolderStatusDelegate::FolderSyncEnabled );
|
||||||
|
|
||||||
|
SyncResult res = f->syncResult();
|
||||||
|
SyncResult::Status status = res.status();
|
||||||
|
|
||||||
|
QString errors = res.errorStrings().join(QLatin1String("<br/>"));
|
||||||
|
|
||||||
|
Theme *theme = Theme::instance();
|
||||||
|
item->setData( theme->statusHeaderText( status ), Qt::ToolTipRole );
|
||||||
|
if( f->syncEnabled() ) {
|
||||||
|
item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole );
|
||||||
|
} else {
|
||||||
|
item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before
|
||||||
|
}
|
||||||
|
item->setData( theme->statusHeaderText( status ), FolderStatusDelegate::FolderStatus );
|
||||||
|
item->setData( errors, FolderStatusDelegate::FolderErrorMsg );
|
||||||
|
|
||||||
|
bool ongoing = false;
|
||||||
|
item->setData( QVariant(res.warnCount()), FolderStatusDelegate::WarningCount );
|
||||||
|
if( status == SyncResult::SyncRunning ) {
|
||||||
|
ongoing = true;
|
||||||
|
}
|
||||||
|
item->setData( ongoing, FolderStatusDelegate::SyncRunning);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotRemoveCurrentFolder()
|
||||||
|
{
|
||||||
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
|
if( selected.isValid() ) {
|
||||||
|
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
|
||||||
|
qDebug() << "Remove Folder alias " << alias;
|
||||||
|
if( !alias.isEmpty() ) {
|
||||||
|
// remove from file system through folder man
|
||||||
|
// _model->removeRow( selected.row() );
|
||||||
|
int ret = QMessageBox::question( this, tr("Confirm Folder Remove"),
|
||||||
|
tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>"
|
||||||
|
"<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias),
|
||||||
|
QMessageBox::Yes|QMessageBox::No );
|
||||||
|
|
||||||
|
if( ret == QMessageBox::No ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
folderMan->slotRemoveFolder( alias );
|
||||||
|
setFolderList(folderMan->map());
|
||||||
|
emit folderChanged();
|
||||||
|
slotCheckConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AccountSettings::slotResetCurrentFolder()
|
||||||
|
{
|
||||||
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
|
if( selected.isValid() ) {
|
||||||
|
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
|
||||||
|
int ret = QMessageBox::question( 0, tr("Confirm Folder Reset"),
|
||||||
|
tr("<p>Do you really want to reset folder <i>%1</i> and rebuild your client database?</p>"
|
||||||
|
"<p><b>Note:</b> This function is designed for maintenance purposes only. "
|
||||||
|
"No files will be removed, but this can cause significant data traffic and "
|
||||||
|
"take several minutes or hours to complete, depending on the size of the folder. "
|
||||||
|
"Only use this option if advised by your administrator.</p>").arg(alias),
|
||||||
|
QMessageBox::Yes|QMessageBox::No );
|
||||||
|
if( ret == QMessageBox::Yes ) {
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
Folder *f = folderMan->folder(alias);
|
||||||
|
f->slotTerminateSync();
|
||||||
|
f->wipe();
|
||||||
|
folderMan->slotScheduleAllFolders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotDoubleClicked( const QModelIndex& indx )
|
||||||
|
{
|
||||||
|
if( ! indx.isValid() ) return;
|
||||||
|
QString alias = _model->data( indx, FolderStatusDelegate::FolderAliasRole ).toString();
|
||||||
|
|
||||||
|
emit openFolderAlias( alias );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotCheckConnection()
|
||||||
|
{
|
||||||
|
if( ownCloudInfo::instance()->isConfigured() ) {
|
||||||
|
connect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
|
||||||
|
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
|
||||||
|
connect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
|
||||||
|
this, SLOT(slotOCInfoFail(QNetworkReply*)));
|
||||||
|
|
||||||
|
ui->connectLabel->setText( tr("Checking %1 connection...").arg(Theme::instance()->appNameGUI()));
|
||||||
|
qDebug() << "Check status.php from statusdialog.";
|
||||||
|
ownCloudInfo::instance()->checkInstallation();
|
||||||
|
} else {
|
||||||
|
// ownCloud is not yet configured.
|
||||||
|
ui->connectLabel->setText( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()));
|
||||||
|
ui->_ButtonAdd->setEnabled( false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::setFolderList( const Folder::Map &folders )
|
||||||
|
{
|
||||||
|
_model->clear();
|
||||||
|
foreach( Folder *f, folders ) {
|
||||||
|
qDebug() << "Folder: " << f;
|
||||||
|
slotAddFolder( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex idx = _model->index(0, 0);
|
||||||
|
if (idx.isValid()) {
|
||||||
|
ui->_folderList->setCurrentIndex(idx);
|
||||||
|
}
|
||||||
|
buttonsSetEnabled();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// move from Application
|
||||||
|
void AccountSettings::slotFolderOpenAction( const QString& alias )
|
||||||
|
{
|
||||||
|
Folder *f = FolderMan::instance()->folder(alias);
|
||||||
|
qDebug() << "opening local url " << f->path();
|
||||||
|
if( f ) {
|
||||||
|
QUrl url(f->path(), QUrl::TolerantMode);
|
||||||
|
url.setScheme( QLatin1String("file") );
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
// work around a bug in QDesktopServices on Win32, see i-net
|
||||||
|
QString filePath = f->path();
|
||||||
|
|
||||||
|
if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
|
||||||
|
url.setUrl(QDir::toNativeSeparators(filePath));
|
||||||
|
else
|
||||||
|
url = QUrl::fromLocalFile(filePath);
|
||||||
|
#endif
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotEnableCurrentFolder()
|
||||||
|
{
|
||||||
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
|
|
||||||
|
if( selected.isValid() ) {
|
||||||
|
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
|
||||||
|
bool folderEnabled = _model->data( selected, FolderStatusDelegate::FolderSyncEnabled).toBool();
|
||||||
|
qDebug() << "Toggle enabled/disabled Folder alias " << alias << " - current state: " << folderEnabled;
|
||||||
|
if( !alias.isEmpty() ) {
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
|
||||||
|
qDebug() << "Application: enable folder with alias " << alias;
|
||||||
|
bool terminate = false;
|
||||||
|
|
||||||
|
// this sets the folder status to disabled but does not interrupt it.
|
||||||
|
Folder *f = folderMan->folder( alias );
|
||||||
|
if( f && folderEnabled ) {
|
||||||
|
// check if a sync is still running and if so, ask if we should terminate.
|
||||||
|
if( f->isBusy() ) { // its still running
|
||||||
|
int reply = QMessageBox::question( 0, tr("Sync Running"),
|
||||||
|
tr("The syncing operation is running.<br/>Do you want to terminate it?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes );
|
||||||
|
if ( reply == QMessageBox::Yes )
|
||||||
|
terminate = true;
|
||||||
|
else
|
||||||
|
return; // do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// message box can return at any time while the thread keeps running,
|
||||||
|
// so better check again after the user has responded.
|
||||||
|
if ( f->isBusy() && terminate )
|
||||||
|
folderMan->terminateSyncProcess( alias );
|
||||||
|
|
||||||
|
folderMan->slotEnableFolder( alias, !folderEnabled );
|
||||||
|
slotUpdateFolderState (f);
|
||||||
|
// set the button text accordingly.
|
||||||
|
slotFolderActivated( selected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotUpdateFolderState( Folder *folder )
|
||||||
|
{
|
||||||
|
QStandardItem *item = 0;
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
if( ! folder ) return;
|
||||||
|
|
||||||
|
item = _model->item( row );
|
||||||
|
|
||||||
|
while( item ) {
|
||||||
|
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder->alias() ) {
|
||||||
|
// its the item to update!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item = _model->item( ++row );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( item ) {
|
||||||
|
folderToModelItem( item, folder );
|
||||||
|
} else {
|
||||||
|
// the dialog is not visible.
|
||||||
|
}
|
||||||
|
slotCheckConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, const QString& version, const QString& )
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
// work around a bug in QDesktopServices on Win32, see i-net
|
||||||
|
QString filePath = url;
|
||||||
|
|
||||||
|
if (filePath.startsWith("\\\\") || filePath.startsWith("//"))
|
||||||
|
_OCUrl.setUrl(QDir::toNativeSeparators(filePath));
|
||||||
|
else
|
||||||
|
_OCUrl = QUrl::fromLocalFile(filePath);
|
||||||
|
#else
|
||||||
|
_OCUrl = QUrl::fromLocalFile(url);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qDebug() << "#-------# oC found on " << url;
|
||||||
|
/* enable the open button */
|
||||||
|
ui->connectLabel->setOpenExternalLinks(true);
|
||||||
|
ui->connectLabel->setText( tr("Connected to <a href=\"%1\">%1</a>.").arg(url) );
|
||||||
|
ui->connectLabel->setToolTip( tr("Version: %1 (%2)").arg(versionStr).arg(version));
|
||||||
|
ui->_ButtonAdd->setEnabled(true);
|
||||||
|
|
||||||
|
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
|
||||||
|
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
|
||||||
|
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
|
||||||
|
this, SLOT(slotOCInfoFail(QNetworkReply*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotOCInfoFail( QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
QString errStr = tr("unknown problem.");
|
||||||
|
if( reply ) errStr = reply->errorString();
|
||||||
|
|
||||||
|
ui->connectLabel->setText( tr("<p>Failed to connect to %1: <tt>%2</tt></p>").arg(Theme::instance()->appNameGUI()).arg(errStr) );
|
||||||
|
ui->_ButtonAdd->setEnabled( false);
|
||||||
|
|
||||||
|
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
|
||||||
|
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
|
||||||
|
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
|
||||||
|
this, SLOT(slotOCInfoFail(QNetworkReply*)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotOpenOC()
|
||||||
|
{
|
||||||
|
if( _OCUrl.isValid() )
|
||||||
|
QDesktopServices::openUrl( _OCUrl );
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItem* AccountSettings::itemForFolder(const QString& folder)
|
||||||
|
{
|
||||||
|
QStandardItem *item = NULL;
|
||||||
|
|
||||||
|
if( folder.isEmpty() ) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
item = _model->item( row );
|
||||||
|
|
||||||
|
while( item ) {
|
||||||
|
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder ) {
|
||||||
|
// its the item to update!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item = _model->item( ++row );
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AccountSettings::shortenFilename( const QString& folder, const QString& file ) const
|
||||||
|
{
|
||||||
|
// strip off the server prefix from the file name
|
||||||
|
QString shortFile(file);
|
||||||
|
if( shortFile.isEmpty() ) {
|
||||||
|
return QString::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shortFile.startsWith(QLatin1String("ownclouds://")) ||
|
||||||
|
shortFile.startsWith(QLatin1String("owncloud://")) ) {
|
||||||
|
// rip off the whole ownCloud URL.
|
||||||
|
Folder *f = FolderMan::instance()->folder(folder);
|
||||||
|
if( f ) {
|
||||||
|
QString remotePathUrl = ownCloudInfo::instance()->webdavUrl() + QLatin1Char('/') + f->secondPath();
|
||||||
|
shortFile.remove(Utility::toCSyncScheme(remotePathUrl));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shortFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem)
|
||||||
|
{
|
||||||
|
Q_UNUSED(problem);
|
||||||
|
|
||||||
|
QStandardItem *item = itemForFolder( folder );
|
||||||
|
if( !item ) return;
|
||||||
|
|
||||||
|
int warnCount = qvariant_cast<int>( item->data(FolderStatusDelegate::WarningCount) );
|
||||||
|
warnCount++;
|
||||||
|
item->setData( QVariant(warnCount), FolderStatusDelegate::WarningCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotSetProgress(const QString& folder, const Progress::Info &progress )
|
||||||
|
{
|
||||||
|
// qDebug() << "================================> Progress for folder " << folder << " file " << file << ": "<< p1;
|
||||||
|
QStandardItem *item = itemForFolder( folder );
|
||||||
|
qint64 prog1 = progress.current_file_bytes;
|
||||||
|
qint64 prog2 = progress.file_size;
|
||||||
|
|
||||||
|
if( item == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotfix for a crash that I experienced in a very rare case/setup
|
||||||
|
if (progress.kind == Mirall::Progress::Invalid) {
|
||||||
|
qDebug() << "================================> INVALID Progress for folder " << folder;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString itemFileName = shortenFilename(folder, progress.current_file);
|
||||||
|
QString syncFileProgressString;
|
||||||
|
|
||||||
|
// stay with the previous kind-string for Context.
|
||||||
|
if( progress.kind != Progress::Context ) {
|
||||||
|
_kindContext = Progress::asActionString(progress.kind);
|
||||||
|
} else {
|
||||||
|
if( _kindContext.isEmpty() ) {
|
||||||
|
// empty kind context means that the dialog was opened after the action
|
||||||
|
// was started.
|
||||||
|
Progress::Kind kind = ProgressDispatcher::instance()->currentFolderContext(progress.folder);
|
||||||
|
if( kind != Progress::Invalid ) {
|
||||||
|
_kindContext = Progress::asActionString(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString kindString = _kindContext;
|
||||||
|
|
||||||
|
switch( progress.kind ) {
|
||||||
|
case Progress::StartSync:
|
||||||
|
item->setData( QVariant(0), FolderStatusDelegate::WarningCount );
|
||||||
|
break;
|
||||||
|
case Progress::StartDownload:
|
||||||
|
case Progress::StartUpload:
|
||||||
|
case Progress::StartDelete:
|
||||||
|
syncFileProgressString = tr("Start");
|
||||||
|
if( _hideProgressTimers.contains(item) ) {
|
||||||
|
// The timer is still running.
|
||||||
|
QTimer *t = _hideProgressTimers.take(item);
|
||||||
|
t->stop();
|
||||||
|
t->deleteLater();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Progress::Context:
|
||||||
|
syncFileProgressString = tr("Currently");
|
||||||
|
break;
|
||||||
|
case Progress::EndDownload:
|
||||||
|
case Progress::EndUpload:
|
||||||
|
case Progress::EndDelete:
|
||||||
|
break;
|
||||||
|
case Progress::EndSync:
|
||||||
|
syncFileProgressString = tr("Completely");
|
||||||
|
|
||||||
|
// start a timer to stop the progress display
|
||||||
|
QTimer *timer;
|
||||||
|
if( _hideProgressTimers.contains(item) ) {
|
||||||
|
timer = _hideProgressTimers[item];
|
||||||
|
// there is already one timer running.
|
||||||
|
} else {
|
||||||
|
timer = new QTimer;
|
||||||
|
connect(timer, SIGNAL(timeout()), this, SLOT(slotHideProgress()));
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
_hideProgressTimers.insert(item, timer);
|
||||||
|
}
|
||||||
|
timer->start(5000);
|
||||||
|
break;
|
||||||
|
case Progress::Invalid:
|
||||||
|
case Progress::Download:
|
||||||
|
case Progress::Upload:
|
||||||
|
case Progress::Inactive:
|
||||||
|
case Progress::Error:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fileProgressString;
|
||||||
|
QString s1 = Utility::octetsToString( prog1 );
|
||||||
|
QString s2 = Utility::octetsToString( prog2 );
|
||||||
|
|
||||||
|
// switch on extra space.
|
||||||
|
item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace );
|
||||||
|
|
||||||
|
if( progress.kind != Progress::EndSync ) {
|
||||||
|
// Example text: "Currently uploading foobar.png (1MB of 2MB)"
|
||||||
|
fileProgressString = tr("%1 %2 %3 (%4 of %5)").arg(syncFileProgressString).arg(kindString).
|
||||||
|
arg(itemFileName).arg(s1).arg(s2);
|
||||||
|
} else {
|
||||||
|
fileProgressString = tr("Completely finished.");
|
||||||
|
}
|
||||||
|
item->setData( fileProgressString,FolderStatusDelegate::SyncProgressItemString);
|
||||||
|
|
||||||
|
// overall progress
|
||||||
|
s1 = Utility::octetsToString( progress.overall_current_bytes );
|
||||||
|
s2 = Utility::octetsToString( progress.overall_transmission_size );
|
||||||
|
QString overallSyncString = tr("%1 of %2, file %3 of %4").arg(s1).arg(s2)
|
||||||
|
.arg(progress.current_file_no).arg(progress.overall_file_count);
|
||||||
|
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
|
||||||
|
|
||||||
|
int overallPercent = 0;
|
||||||
|
if( progress.overall_transmission_size > 0 ) {
|
||||||
|
overallPercent = qRound(double(progress.overall_current_bytes)/double(progress.overall_transmission_size) * 100.0);
|
||||||
|
}
|
||||||
|
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotHideProgress()
|
||||||
|
{
|
||||||
|
QTimer *send_timer = qobject_cast<QTimer*>(this->sender());
|
||||||
|
QHash<QStandardItem*, QTimer*>::const_iterator i = _hideProgressTimers.constBegin();
|
||||||
|
while (i != _hideProgressTimers.constEnd()) {
|
||||||
|
if( i.value() == send_timer ) {
|
||||||
|
QStandardItem *item = i.key();
|
||||||
|
item->setData( QVariant(false), FolderStatusDelegate::AddProgressSpace );
|
||||||
|
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressOverallString );
|
||||||
|
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressItemString );
|
||||||
|
item->setData( 0, FolderStatusDelegate::SyncProgressOverallPercent );
|
||||||
|
|
||||||
|
ui->_folderList->repaint();
|
||||||
|
_hideProgressTimers.remove(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_timer->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
|
||||||
|
{
|
||||||
|
ui->quotaProgressBar->setEnabled(true);
|
||||||
|
// workaround the label only accepting ints (which may be only 32 bit wide)
|
||||||
|
ui->quotaProgressBar->setMaximum(100);
|
||||||
|
ui->quotaProgressBar->setValue(round(used/(double)total * 100));
|
||||||
|
QString usedStr = Utility::octetsToString(used);
|
||||||
|
QString totalStr = Utility::octetsToString(total);
|
||||||
|
ui->quotaLabel->setText(tr("%1 of %2 in use.").arg(usedStr, totalStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotIgnoreFilesEditor()
|
||||||
|
{
|
||||||
|
if (_ignoreEditor.isNull()) {
|
||||||
|
_ignoreEditor = new IgnoreListEditor(this);
|
||||||
|
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
|
||||||
|
_ignoreEditor->open();
|
||||||
|
} else {
|
||||||
|
Utility::raiseDialog(_ignoreEditor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSettings::slotInfoAboutCurrentFolder()
|
||||||
|
{
|
||||||
|
emit(openProgressDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountSettings::~AccountSettings()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
107
src/mirall/accountsettings.h
Normal file
107
src/mirall/accountsettings.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ACCOUNTSETTINGS_H
|
||||||
|
#define ACCOUNTSETTINGS_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QStandardItem>
|
||||||
|
|
||||||
|
#include "mirall/folder.h"
|
||||||
|
#include "mirall/progressdispatcher.h"
|
||||||
|
#include "mirall/itemprogressdialog.h"
|
||||||
|
|
||||||
|
class QStandardItemModel;
|
||||||
|
class QModelIndex;
|
||||||
|
class QStandardItem;
|
||||||
|
class QNetworkReply;
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class AccountSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FolderMan;
|
||||||
|
class ItemProgressDialog;
|
||||||
|
class IgnoreListEditor;
|
||||||
|
|
||||||
|
class AccountSettings : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AccountSettings(QWidget *parent = 0);
|
||||||
|
~AccountSettings();
|
||||||
|
|
||||||
|
void setFolderList( const Folder::Map& );
|
||||||
|
void buttonsSetEnabled();
|
||||||
|
void setListWidgetItem(QListWidgetItem* item);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void folderChanged();
|
||||||
|
void openProgressDialog();
|
||||||
|
void openFolderAlias( const QString& );
|
||||||
|
void infoFolderAlias( const QString& );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void slotFolderActivated( const QModelIndex& );
|
||||||
|
void slotOpenOC();
|
||||||
|
void slotUpdateFolderState( Folder* );
|
||||||
|
void slotCheckConnection();
|
||||||
|
void slotOCInfo( const QString&, const QString&, const QString&, const QString& );
|
||||||
|
void slotOCInfoFail( QNetworkReply* );
|
||||||
|
void slotDoubleClicked( const QModelIndex& );
|
||||||
|
void slotFolderOpenAction( const QString& );
|
||||||
|
void slotSetProgress(const QString&, const Progress::Info& progress);
|
||||||
|
void slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem);
|
||||||
|
|
||||||
|
void slotUpdateQuota( qint64,qint64 );
|
||||||
|
void slotIgnoreFilesEditor();
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void slotAddFolder();
|
||||||
|
void slotAddFolder( Folder* );
|
||||||
|
void slotEnableCurrentFolder();
|
||||||
|
void slotRemoveCurrentFolder();
|
||||||
|
void slotInfoAboutCurrentFolder();
|
||||||
|
void slotResetCurrentFolder();
|
||||||
|
void slotFolderWizardAccepted();
|
||||||
|
void slotFolderWizardRejected();
|
||||||
|
void slotOpenAccountWizard();
|
||||||
|
void slotHideProgress();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString shortenFilename( const QString& folder, const QString& file ) const;
|
||||||
|
void folderToModelItem( QStandardItem *, Folder * );
|
||||||
|
QStandardItem* itemForFolder(const QString& );
|
||||||
|
|
||||||
|
Ui::AccountSettings *ui;
|
||||||
|
QPointer<ItemProgressDialog> _fileItemDialog;
|
||||||
|
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||||
|
QStandardItemModel *_model;
|
||||||
|
QListWidgetItem *_item;
|
||||||
|
QUrl _OCUrl;
|
||||||
|
QHash<QStandardItem*, QTimer*> _hideProgressTimers;
|
||||||
|
QString _kindContext;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
|
||||||
|
#endif // ACCOUNTSETTINGS_H
|
||||||
163
src/mirall/accountsettings.ui
Normal file
163
src/mirall/accountsettings.ui
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Mirall::AccountSettings</class>
|
||||||
|
<widget class="QWidget" name="Mirall::AccountSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>607</width>
|
||||||
|
<height>382</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QGroupBox" name="maintenanceGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Account Maintenance</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ignoredFilesButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Ignored Files</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="modifyAccountButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Modify Account</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="syncStatusGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Sync Status</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="connectLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connected with <server> as <user></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QListView" name="_folderList"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="_ButtonAdd">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Folder...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="_ButtonEnable">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pause</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="_ButtonRemove">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="_ButtonInfo">
|
||||||
|
<property name="text">
|
||||||
|
<string>Info...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="storageGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Storage Usage</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="quotaProgressBar">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="quotaLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Retrieving usage information...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string><b>Note:</b> Some folders, including network mounted or shared folders, might have different limits.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -18,15 +18,16 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QSslError>
|
#include <QSslError>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
#include "qtsingleapplication.h"
|
#include "qtsingleapplication.h"
|
||||||
|
|
||||||
#include "mirall/syncresult.h"
|
#include "mirall/syncresult.h"
|
||||||
#include "mirall/folder.h"
|
|
||||||
#include "mirall/logbrowser.h"
|
#include "mirall/logbrowser.h"
|
||||||
#include "mirall/folderman.h"
|
|
||||||
#include "mirall/fileitemdialog.h"
|
|
||||||
#include "mirall/systray.h"
|
#include "mirall/systray.h"
|
||||||
|
#include "mirall/connectionvalidator.h"
|
||||||
|
#include "mirall/progressdispatcher.h"
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
@@ -37,13 +38,13 @@ class QNetworkReply;
|
|||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
class Theme;
|
class Theme;
|
||||||
|
class Folder;
|
||||||
class FolderWatcher;
|
class FolderWatcher;
|
||||||
class FolderWizard;
|
class FolderWizard;
|
||||||
class StatusDialog;
|
|
||||||
class OwncloudSetupWizard;
|
|
||||||
class ownCloudInfo;
|
class ownCloudInfo;
|
||||||
class SslErrorDialog;
|
class SslErrorDialog;
|
||||||
class UpdateDetector;
|
class SettingsDialog;
|
||||||
|
class ItemProgressDialog;
|
||||||
|
|
||||||
class Application : public SharedTools::QtSingleApplication
|
class Application : public SharedTools::QtSingleApplication
|
||||||
{
|
{
|
||||||
@@ -55,32 +56,19 @@ public:
|
|||||||
bool giveHelp();
|
bool giveHelp();
|
||||||
void showHelp();
|
void showHelp();
|
||||||
|
|
||||||
signals:
|
public slots:
|
||||||
|
// TODO: this should not be public
|
||||||
protected slots:
|
|
||||||
void slotAddFolder();
|
|
||||||
void slotOpenStatus();
|
|
||||||
void slotRemoveFolder( const QString& );
|
|
||||||
void slotResetFolder( const QString& );
|
|
||||||
void slotEnableFolder( const QString&, const bool );
|
|
||||||
void slotInfoFolder( const QString& );
|
|
||||||
void slotConfigure();
|
|
||||||
void slotConfigureProxy();
|
|
||||||
void slotParseOptions( const QString& );
|
|
||||||
void slotShowTrayMessage(const QString&, const QString&);
|
|
||||||
|
|
||||||
void slotSyncStateChange( const QString& );
|
|
||||||
void slotownCloudWizardDone(int);
|
void slotownCloudWizardDone(int);
|
||||||
protected:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
void parseOptions(const QStringList& );
|
void parseOptions(const QStringList& );
|
||||||
void setupTranslations();
|
void setupTranslations();
|
||||||
void setupActions();
|
void setupActions();
|
||||||
void setupSystemTray();
|
void setupSystemTray();
|
||||||
void setupContextMenu();
|
void setupContextMenu();
|
||||||
void setupLogBrowser();
|
void setupLogBrowser();
|
||||||
void setupProxy();
|
|
||||||
void enterNextLogFile();
|
void enterNextLogFile();
|
||||||
|
bool checkConfigExists(bool openSettings);
|
||||||
|
|
||||||
//folders have to be disabled while making config changes
|
//folders have to be disabled while making config changes
|
||||||
void computeOverallSyncStatus();
|
void computeOverallSyncStatus();
|
||||||
@@ -90,56 +78,69 @@ protected:
|
|||||||
bool winEventFilter( MSG * message, long * result );
|
bool winEventFilter( MSG * message, long * result );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void folderRemoved();
|
||||||
|
void folderStateChanged(Folder*);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
void slotFoldersChanged();
|
||||||
|
void slotSettings();
|
||||||
|
void slotItemProgressDialog();
|
||||||
|
void slotParseOptions( const QString& );
|
||||||
|
void slotShowTrayMessage(const QString&, const QString&);
|
||||||
|
void slotShowOptionalTrayMessage(const QString&, const QString&);
|
||||||
|
void slotShowGuiMessage(const QString& title, const QString& message);
|
||||||
|
void slotCheckConnection();
|
||||||
|
void slotConnectionValidatorResult(ConnectionValidator::Status);
|
||||||
|
void slotSyncStateChange( const QString& );
|
||||||
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
|
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
|
||||||
void slotFolderOpenAction(const QString & );
|
void slotFolderOpenAction(const QString & );
|
||||||
void slotOpenOwnCloud();
|
void slotOpenOwnCloud();
|
||||||
void slotStartFolderSetup(int result = QDialog::Accepted); // defaulting to Accepted
|
|
||||||
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
|
|
||||||
void slotNoOwnCloudFound( QNetworkReply* );
|
|
||||||
void slotCheckAuthentication();
|
|
||||||
void slotAuthCheck( const QString& ,QNetworkReply* );
|
|
||||||
void slotOpenLogBrowser();
|
void slotOpenLogBrowser();
|
||||||
void slotAbout();
|
|
||||||
void slotSSLFailed( QNetworkReply *reply, QList<QSslError> errors );
|
void slotSSLFailed( QNetworkReply *reply, QList<QSslError> errors );
|
||||||
void slotFetchCredentials();
|
|
||||||
void slotCredentialsFetched( bool );
|
|
||||||
void slotStartUpdateDetector();
|
void slotStartUpdateDetector();
|
||||||
|
void slotSetupProxy();
|
||||||
|
void slotRefreshQuotaDisplay( qint64 total, qint64 used );
|
||||||
|
void slotUseMonoIconsChanged( bool );
|
||||||
|
void slotUpdateProgress(const QString&, const Progress::Info&);
|
||||||
|
void slotProgressSyncProblem(const QString& folder, const Progress::SyncProblem &problem);
|
||||||
|
void slotDisplayIdle();
|
||||||
|
void slotHelp();
|
||||||
|
void slotCredentialsFetched();
|
||||||
private:
|
private:
|
||||||
void setHelp();
|
void setHelp();
|
||||||
void raiseDialog( QWidget* );
|
void raiseDialog( QWidget* );
|
||||||
|
void rebuildRecentMenus();
|
||||||
|
void runValidator();
|
||||||
|
|
||||||
// configuration file -> folder
|
|
||||||
Systray *_tray;
|
Systray *_tray;
|
||||||
QAction *_actionQuit;
|
|
||||||
QAction *_actionAddFolder;
|
|
||||||
QAction *_actionOpenStatus;
|
|
||||||
QAction *_actionConfigure;
|
|
||||||
QAction *_actionOpenoC;
|
QAction *_actionOpenoC;
|
||||||
QAction *_actionConfigureProxy;
|
QAction *_actionSettings;
|
||||||
QAction *_actionAbout;
|
QAction *_actionQuota;
|
||||||
|
QAction *_actionStatus;
|
||||||
|
QAction *_actionRecent;
|
||||||
|
QAction *_actionHelp;
|
||||||
|
QAction *_actionQuit;
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
QNetworkConfigurationManager *_networkMgr;
|
QNetworkConfigurationManager *_networkMgr;
|
||||||
#endif
|
|
||||||
|
|
||||||
FolderWizard *_folderWizard;
|
QPointer<FolderWizard> _folderWizard;
|
||||||
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
|
|
||||||
SslErrorDialog *_sslErrorDialog;
|
SslErrorDialog *_sslErrorDialog;
|
||||||
|
ConnectionValidator *_conValidator;
|
||||||
|
|
||||||
// tray's menu
|
// tray's menu
|
||||||
QMenu *_contextMenu;
|
QMenu *_contextMenu;
|
||||||
StatusDialog *_statusDialog;
|
QMenu *_recentActionsMenu;
|
||||||
FileItemDialog *_fileItemDialog;
|
|
||||||
|
|
||||||
FolderMan *_folderMan;
|
|
||||||
Theme *_theme;
|
Theme *_theme;
|
||||||
QSignalMapper *_folderOpenActionMapper;
|
QSignalMapper *_folderOpenActionMapper;
|
||||||
UpdateDetector *_updateDetector;
|
|
||||||
LogBrowser *_logBrowser;
|
LogBrowser *_logBrowser;
|
||||||
|
QPointer<SettingsDialog> _settingsDialog;
|
||||||
|
QPointer<ItemProgressDialog> _progressDialog;
|
||||||
|
|
||||||
QString _logFile;
|
QString _logFile;
|
||||||
QString _logDirectory;
|
QString _logDirectory;
|
||||||
|
|
||||||
int _logExpire;
|
int _logExpire;
|
||||||
bool _showLogWindow;
|
bool _showLogWindow;
|
||||||
bool _logFlush;
|
bool _logFlush;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "mirall/owncloudinfo.h"
|
#include "mirall/owncloudinfo.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
#include "mirall/credentialstore.h"
|
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
@@ -28,7 +27,8 @@ ConnectionValidator::ConnectionValidator(QObject *parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConnectionValidator::ConnectionValidator(const QString& connection, QObject *parent)
|
ConnectionValidator::ConnectionValidator(const QString& connection, QObject *parent)
|
||||||
:_connection(connection)
|
: QObject(parent),
|
||||||
|
_connection(connection)
|
||||||
{
|
{
|
||||||
ownCloudInfo::instance()->setCustomConfigHandle(_connection);
|
ownCloudInfo::instance()->setCustomConfigHandle(_connection);
|
||||||
}
|
}
|
||||||
@@ -38,9 +38,42 @@ QStringList ConnectionValidator::errors() const
|
|||||||
return _errors;
|
return _errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ConnectionValidator::statusString( Status )
|
QString ConnectionValidator::statusString( Status stat ) const
|
||||||
{
|
{
|
||||||
return QLatin1String("Get your street creds!");
|
QString re;
|
||||||
|
|
||||||
|
switch( stat ) {
|
||||||
|
case Undefined:
|
||||||
|
re = QLatin1String("Undefined");
|
||||||
|
break;
|
||||||
|
case Connected:
|
||||||
|
re = QLatin1String("Connected");
|
||||||
|
break;
|
||||||
|
case NotConfigured:
|
||||||
|
re = QLatin1String("NotConfigured");
|
||||||
|
break;
|
||||||
|
case ServerVersionMismatch:
|
||||||
|
re = QLatin1String("Server Version Mismatch");
|
||||||
|
break;
|
||||||
|
case CredentialsTooManyAttempts:
|
||||||
|
re = QLatin1String("Credentials Too Many Attempts");
|
||||||
|
break;
|
||||||
|
case CredentialError:
|
||||||
|
re = QLatin1String("CredentialError");
|
||||||
|
break;
|
||||||
|
case CredentialsUserCanceled:
|
||||||
|
re = QLatin1String("Credential User Canceled");
|
||||||
|
break;
|
||||||
|
case CredentialsWrong:
|
||||||
|
re = QLatin1String("Credentials Wrong");
|
||||||
|
break;
|
||||||
|
case StatusNotFound:
|
||||||
|
re = QLatin1String("Status not found");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
re = QLatin1String("status undeclared.");
|
||||||
|
}
|
||||||
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +93,7 @@ void ConnectionValidator::checkConnection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& edition)
|
void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& /*edition*/)
|
||||||
{
|
{
|
||||||
// status.php was found.
|
// status.php was found.
|
||||||
qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")";
|
qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")";
|
||||||
@@ -82,7 +115,7 @@ void ConnectionValidator::slotStatusFound( const QString& url, const QString& ve
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTimer::singleShot( 0, this, SLOT( slotFetchCredentials() ));
|
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
|
||||||
}
|
}
|
||||||
|
|
||||||
// status.php could not be loaded.
|
// status.php could not be loaded.
|
||||||
@@ -100,77 +133,19 @@ void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionValidator::slotFetchCredentials()
|
|
||||||
{
|
|
||||||
if( _connection.isEmpty() ) {
|
|
||||||
if( CredentialStore::instance()->canTryAgain() ) {
|
|
||||||
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
|
|
||||||
this, SLOT(slotCredentialsFetched(bool)) );
|
|
||||||
CredentialStore::instance()->fetchCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
|
|
||||||
_errors << tr("Too many attempts to get a valid password.");
|
|
||||||
emit connectionResult( CredentialsTooManyAttempts );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Pull credentials from Mirall config.
|
|
||||||
slotCredentialsFetched( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConnectionValidator::slotCredentialsFetched( bool ok )
|
|
||||||
{
|
|
||||||
qDebug() << "Credentials successfully fetched: " << ok;
|
|
||||||
disconnect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)) );
|
|
||||||
|
|
||||||
if( ! ok ) {
|
|
||||||
Status stat;
|
|
||||||
_errors << tr("Error: Could not retrieve the password!");
|
|
||||||
|
|
||||||
if( CredentialStore::instance()->state() == CredentialStore::UserCanceled ) {
|
|
||||||
_errors << tr("Password dialog was canceled!");
|
|
||||||
stat = CredentialsUserCanceled;
|
|
||||||
} else {
|
|
||||||
_errors << CredentialStore::instance()->errorMessage();
|
|
||||||
stat = CredentialError;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Could not fetch credentials" << _errors;
|
|
||||||
|
|
||||||
emit connectionResult( stat );
|
|
||||||
} else {
|
|
||||||
QString user, pwd;
|
|
||||||
if( _connection.isEmpty() ) {
|
|
||||||
user = CredentialStore::instance()->user();
|
|
||||||
pwd = CredentialStore::instance()->password();
|
|
||||||
} else {
|
|
||||||
// in case of reconfiguration, the _connection is set.
|
|
||||||
MirallConfigFile cfg(_connection);
|
|
||||||
user = cfg.ownCloudUser();
|
|
||||||
pwd = cfg.ownCloudPasswd();
|
|
||||||
}
|
|
||||||
ownCloudInfo::instance()->setCredentials( user, pwd );
|
|
||||||
|
|
||||||
// Credential fetched ok.
|
|
||||||
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConnectionValidator::slotCheckAuthentication()
|
void ConnectionValidator::slotCheckAuthentication()
|
||||||
{
|
{
|
||||||
connect( ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
connect( ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
||||||
this, SLOT(slotAuthCheck(QString,QNetworkReply*)));
|
this, SLOT(slotAuthCheck(QString,QNetworkReply*)));
|
||||||
|
|
||||||
qDebug() << "# checking for authentication settings.";
|
qDebug() << "# checking for authentication settings.";
|
||||||
ownCloudInfo::instance()->getRequest(QLatin1String("/"), true ); // this call needs to be authenticated.
|
ownCloudInfo::instance()->getWebDAVPath(QLatin1String("/") ); // this call needs to be authenticated.
|
||||||
// simply GET the webdav root, will fail if credentials are wrong.
|
// simply GET the webdav root, will fail if credentials are wrong.
|
||||||
// continue in slotAuthCheck here :-)
|
// continue in slotAuthCheck here :-)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
|
void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
|
||||||
{
|
{
|
||||||
bool ok = true;
|
|
||||||
Status stat = Connected;
|
Status stat = Connected;
|
||||||
|
|
||||||
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
|
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
|
||||||
@@ -178,7 +153,6 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
|
|||||||
qDebug() << "******** Password is wrong!";
|
qDebug() << "******** Password is wrong!";
|
||||||
_errors << "The provided credentials are wrong.";
|
_errors << "The provided credentials are wrong.";
|
||||||
stat = CredentialsWrong;
|
stat = CredentialsWrong;
|
||||||
ok = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnect from ownCloud Info signals
|
// disconnect from ownCloud Info signals
|
||||||
@@ -186,7 +160,6 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
|
|||||||
this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
|
this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
|
||||||
|
|
||||||
emit connectionResult( stat );
|
emit connectionResult( stat );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ public:
|
|||||||
|
|
||||||
void checkConnection();
|
void checkConnection();
|
||||||
|
|
||||||
QString statusString( Status );
|
QString statusString( Status ) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionResult( ConnectionValidator::Status );
|
void connectionResult( ConnectionValidator::Status );
|
||||||
void connectionAvailable();
|
// void connectionAvailable();
|
||||||
void connectionFailed();
|
// void connectionFailed();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
@@ -58,8 +58,6 @@ protected slots:
|
|||||||
void slotStatusFound( const QString&, const QString&, const QString&, const QString& );
|
void slotStatusFound( const QString&, const QString&, const QString&, const QString& );
|
||||||
void slotNoStatusFound(QNetworkReply *);
|
void slotNoStatusFound(QNetworkReply *);
|
||||||
|
|
||||||
void slotFetchCredentials();
|
|
||||||
void slotCredentialsFetched( bool );
|
|
||||||
void slotCheckAuthentication();
|
void slotCheckAuthentication();
|
||||||
void slotAuthCheck( const QString& ,QNetworkReply * );
|
void slotAuthCheck( const QString& ,QNetworkReply * );
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
#include "mirall/logger.h"
|
#include "mirall/logger.h"
|
||||||
#include "mirall/owncloudinfo.h"
|
#include "mirall/owncloudinfo.h"
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -232,6 +233,20 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch( file->type ) {
|
||||||
|
case CSYNC_FTW_TYPE_DIR:
|
||||||
|
item._type = SyncFileItem::Directory;
|
||||||
|
break;
|
||||||
|
case CSYNC_FTW_TYPE_FILE:
|
||||||
|
item._type = SyncFileItem::File;
|
||||||
|
break;
|
||||||
|
case CSYNC_FTW_TYPE_SLINK:
|
||||||
|
item._type = SyncFileItem::SoftLink;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
item._type = SyncFileItem::UnknownType;
|
||||||
|
}
|
||||||
|
|
||||||
item._dir = dir;
|
item._dir = dir;
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
_syncedItems.append(item);
|
_syncedItems.append(item);
|
||||||
@@ -242,7 +257,7 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
|
|
||||||
int CSyncThread::treewalkError(TREE_WALK_FILE* file)
|
int CSyncThread::treewalkError(TREE_WALK_FILE* file)
|
||||||
{
|
{
|
||||||
SyncFileItem item;
|
SyncFileItem item; // only used for search.
|
||||||
item._file= QString::fromUtf8(file->path);
|
item._file= QString::fromUtf8(file->path);
|
||||||
int indx = _syncedItems.indexOf(item);
|
int indx = _syncedItems.indexOf(item);
|
||||||
|
|
||||||
@@ -251,9 +266,10 @@ int CSyncThread::treewalkError(TREE_WALK_FILE* file)
|
|||||||
|
|
||||||
if( file &&
|
if( file &&
|
||||||
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
|
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
|
||||||
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
|
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
_syncedItems[indx]._instruction = file->instruction;
|
_syncedItems[indx]._instruction = file->instruction;
|
||||||
|
_syncedItems[indx]._errorString = QString::fromUtf8(file->error_string);
|
||||||
_mutex.unlock();
|
_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,11 +331,50 @@ void CSyncThread::startSync()
|
|||||||
// cleans up behind us and emits finished() to ease error handling
|
// cleans up behind us and emits finished() to ease error handling
|
||||||
CSyncRunScopeHelper helper(_csync_ctx, this);
|
CSyncRunScopeHelper helper(_csync_ctx, this);
|
||||||
|
|
||||||
|
// maybe move this somewhere else where it can influence a running sync?
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
|
||||||
|
int downloadLimit = 0;
|
||||||
|
if (cfg.useDownloadLimit()) {
|
||||||
|
downloadLimit = cfg.downloadLimit() * 1000;
|
||||||
|
}
|
||||||
|
csync_set_module_property(_csync_ctx, "bandwidth_limit_download", &downloadLimit);
|
||||||
|
|
||||||
|
int uploadLimit = -75; // 75%
|
||||||
|
int useUpLimit = cfg.useUploadLimit();
|
||||||
|
if ( useUpLimit >= 1) {
|
||||||
|
uploadLimit = cfg.uploadLimit() * 1000;
|
||||||
|
} else if (useUpLimit == 0) {
|
||||||
|
uploadLimit = 0;
|
||||||
|
}
|
||||||
|
csync_set_module_property(_csync_ctx, "bandwidth_limit_upload", &uploadLimit);
|
||||||
|
|
||||||
|
csync_set_progress_callback( _csync_ctx, cb_progress );
|
||||||
|
|
||||||
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
||||||
csync_set_userdata(_csync_ctx, this);
|
csync_set_userdata(_csync_ctx, this);
|
||||||
|
|
||||||
|
// TODO: This should be a part of this method, but we don't have
|
||||||
|
// any way to get "session_key" module property from csync. Had we
|
||||||
|
// have it, then we could keep this code and remove it from
|
||||||
|
// AbstractCredentials implementations.
|
||||||
|
cfg.getCredentials()->syncContextPreStart(_csync_ctx);
|
||||||
|
// if (_lastAuthCookies.length() > 0) {
|
||||||
|
// // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
|
||||||
|
// // when https://github.com/owncloud/core/pull/4042 is merged.
|
||||||
|
// QString cookiesAsString;
|
||||||
|
// foreach(QNetworkCookie c, _lastAuthCookies) {
|
||||||
|
// cookiesAsString += c.name();
|
||||||
|
// cookiesAsString += '=';
|
||||||
|
// cookiesAsString += c.value();
|
||||||
|
// cookiesAsString += "; ";
|
||||||
|
// }
|
||||||
|
// csync_set_module_property(_csync_ctx, "session_key", cookiesAsString.to
|
||||||
|
// }
|
||||||
|
|
||||||
// csync_set_auth_callback( _csync_ctx, getauth );
|
// csync_set_auth_callback( _csync_ctx, getauth );
|
||||||
csync_set_progress_callback( _csync_ctx, progress );
|
|
||||||
|
|
||||||
|
|
||||||
qDebug() << "#### Update start #################################################### >>";
|
qDebug() << "#### Update start #################################################### >>";
|
||||||
if( csync_update(_csync_ctx) < 0 ) {
|
if( csync_update(_csync_ctx) < 0 ) {
|
||||||
@@ -329,7 +384,7 @@ void CSyncThread::startSync()
|
|||||||
qDebug() << "<<#### Update end ###########################################################";
|
qDebug() << "<<#### Update end ###########################################################";
|
||||||
|
|
||||||
if( csync_reconcile(_csync_ctx) < 0 ) {
|
if( csync_reconcile(_csync_ctx) < 0 ) {
|
||||||
handleSyncError(_csync_ctx, "cysnc_reconcile");
|
handleSyncError(_csync_ctx, "csync_reconcile");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +418,7 @@ void CSyncThread::startSync()
|
|||||||
|
|
||||||
if( walkOk ) {
|
if( walkOk ) {
|
||||||
if( csync_walk_local_tree(_csync_ctx, &walkFinalize, 0) < 0 ||
|
if( csync_walk_local_tree(_csync_ctx, &walkFinalize, 0) < 0 ||
|
||||||
csync_walk_remote_tree( _csync_ctx, &walkFinalize, 0 ) < 0 ) {
|
csync_walk_remote_tree(_csync_ctx, &walkFinalize, 0 ) < 0 ) {
|
||||||
qDebug() << "Error in finalize treewalk.";
|
qDebug() << "Error in finalize treewalk.";
|
||||||
} else {
|
} else {
|
||||||
// emit the treewalk results.
|
// emit the treewalk results.
|
||||||
@@ -373,16 +428,78 @@ void CSyncThread::startSync()
|
|||||||
qDebug() << Q_FUNC_INFO << "Sync finished";
|
qDebug() << Q_FUNC_INFO << "Sync finished";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSyncThread::progress(const char *remote_url, enum csync_notify_type_e kind,
|
Progress::Kind CSyncThread::csyncToProgressKind( enum csync_notify_type_e kind )
|
||||||
long long o1, long long o2, void *userdata)
|
|
||||||
{
|
{
|
||||||
(void) o1; (void) o2;
|
Progress::Kind pKind = Progress::Invalid;
|
||||||
if (kind == CSYNC_NOTIFY_FINISHED_DOWNLOAD) {
|
|
||||||
QString path = QUrl::fromEncoded(remote_url).toString();
|
switch(kind) {
|
||||||
CSyncThread *thread = static_cast<CSyncThread*>(userdata);
|
case CSYNC_NOTIFY_INVALID:
|
||||||
thread->fileReceived(path);
|
pKind = Progress::Invalid;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_START_SYNC_SEQUENCE:
|
||||||
|
pKind = Progress::StartSync;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_START_DOWNLOAD:
|
||||||
|
pKind = Progress::StartDownload;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_START_UPLOAD:
|
||||||
|
pKind = Progress::StartUpload;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_PROGRESS:
|
||||||
|
pKind = Progress::Context;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_FINISHED_DOWNLOAD:
|
||||||
|
pKind = Progress::EndDownload;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_FINISHED_UPLOAD:
|
||||||
|
pKind = Progress::EndUpload;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_FINISHED_SYNC_SEQUENCE:
|
||||||
|
pKind = Progress::EndSync;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_START_DELETE:
|
||||||
|
pKind = Progress::StartDelete;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_END_DELETE:
|
||||||
|
pKind = Progress::EndDelete;
|
||||||
|
break;
|
||||||
|
case CSYNC_NOTIFY_ERROR:
|
||||||
|
pKind = Progress::Error;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pKind = Progress::Invalid;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return pKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSyncThread::cb_progress( CSYNC_PROGRESS *progress, void *userdata )
|
||||||
|
{
|
||||||
|
if( !progress ) {
|
||||||
|
qDebug() << "No progress block in progress callback found!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( !userdata ) {
|
||||||
|
qDebug() << "No thread given in progress callback!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Progress::Info pInfo;
|
||||||
|
CSyncThread *thread = static_cast<CSyncThread*>(userdata);
|
||||||
|
|
||||||
|
pInfo.kind = thread->csyncToProgressKind( progress->kind );
|
||||||
|
pInfo.current_file = QUrl::fromEncoded( progress->path ).toString();
|
||||||
|
pInfo.file_size = progress->file_size;
|
||||||
|
pInfo.current_file_bytes = progress->curr_bytes;
|
||||||
|
|
||||||
|
pInfo.overall_file_count = progress->overall_file_count;
|
||||||
|
pInfo.current_file_no = progress->current_file_no;
|
||||||
|
pInfo.overall_transmission_size = progress->overall_transmission_size;
|
||||||
|
pInfo.overall_current_bytes = progress->current_overall_bytes;
|
||||||
|
pInfo.timestamp = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
// Connect to something in folder!
|
||||||
|
thread->transmissionProgress( pInfo );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|||||||
@@ -22,10 +22,12 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
|
#include <QNetworkCookie>
|
||||||
|
|
||||||
#include <csync.h>
|
#include <csync.h>
|
||||||
|
|
||||||
#include "mirall/syncfileitem.h"
|
#include "mirall/syncfileitem.h"
|
||||||
|
#include "mirall/progressdispatcher.h"
|
||||||
|
|
||||||
class QProcess;
|
class QProcess;
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ signals:
|
|||||||
void csyncUnavailable();
|
void csyncUnavailable();
|
||||||
void treeWalkResult(const SyncFileItemVector&);
|
void treeWalkResult(const SyncFileItemVector&);
|
||||||
|
|
||||||
|
void transmissionProgress( const Progress::Info& progress );
|
||||||
void csyncStateDbFile( const QString& );
|
void csyncStateDbFile( const QString& );
|
||||||
void wipeDb();
|
void wipeDb();
|
||||||
|
|
||||||
@@ -60,16 +63,15 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void handleSyncError(CSYNC *ctx, const char *state);
|
void handleSyncError(CSYNC *ctx, const char *state);
|
||||||
static void progress(const char *remote_url,
|
|
||||||
enum csync_notify_type_e kind,
|
static void cb_progress( CSYNC_PROGRESS *progress, void *userdata );
|
||||||
long long o1, long long o2,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
static int treewalkLocal( TREE_WALK_FILE*, void *);
|
static int treewalkLocal( TREE_WALK_FILE*, void *);
|
||||||
static int treewalkRemote( TREE_WALK_FILE*, void *);
|
static int treewalkRemote( TREE_WALK_FILE*, void *);
|
||||||
int treewalkFile( TREE_WALK_FILE*, bool );
|
int treewalkFile( TREE_WALK_FILE*, bool );
|
||||||
int treewalkError( TREE_WALK_FILE* );
|
int treewalkError( TREE_WALK_FILE* );
|
||||||
|
|
||||||
|
Progress::Kind csyncToProgressKind( enum csync_notify_type_e kind );
|
||||||
static int walkFinalize(TREE_WALK_FILE*, void* );
|
static int walkFinalize(TREE_WALK_FILE*, void* );
|
||||||
|
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ private:
|
|||||||
|
|
||||||
bool _hasFiles; // true if there is at least one file that is not ignored or removed
|
bool _hasFiles; // true if there is at least one file that is not ignored or removed
|
||||||
|
|
||||||
friend class CSyncRunScopeHelper;
|
friend struct CSyncRunScopeHelper;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,304 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; version 2 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QtGui>
|
|
||||||
|
|
||||||
#include "mirall/fileitemdialog.h"
|
|
||||||
#include "mirall/theme.h"
|
|
||||||
#include "mirall/syncresult.h"
|
|
||||||
#include "mirall/logger.h"
|
|
||||||
|
|
||||||
#define TYPE_SUCCESS 1
|
|
||||||
#define TYPE_CONFLICT 2
|
|
||||||
#define TYPE_NEW 3
|
|
||||||
#define TYPE_DELETED 4
|
|
||||||
#define TYPE_ERROR 5
|
|
||||||
#define TYPE_RENAME 6
|
|
||||||
#define TYPE_IGNORE 7
|
|
||||||
|
|
||||||
#define FILE_TYPE 100
|
|
||||||
|
|
||||||
namespace Mirall {
|
|
||||||
|
|
||||||
FileItemDialog::FileItemDialog(Theme *theme, QWidget *parent) :
|
|
||||||
QDialog(parent),
|
|
||||||
_theme(theme)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
connect(_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
|
|
||||||
this, SLOT(accept()));
|
|
||||||
|
|
||||||
QStringList header;
|
|
||||||
header << tr("Files");
|
|
||||||
QString firstColString = tr("File Count");
|
|
||||||
header << firstColString;
|
|
||||||
_treeWidget->setHeaderLabels( header );
|
|
||||||
|
|
||||||
_treeWidget->setColumnWidth(0, 480);
|
|
||||||
_timer.setInterval(1000);
|
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotSetFolderMessage()));
|
|
||||||
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
|
||||||
|
|
||||||
QPushButton *copyBtn = _dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
|
||||||
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
|
|
||||||
|
|
||||||
setWindowTitle(tr("Sync Protocol"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::setSyncResult( const SyncResult& result )
|
|
||||||
{
|
|
||||||
QString folderMessage;
|
|
||||||
|
|
||||||
SyncResult::Status syncStatus = result.status();
|
|
||||||
switch( syncStatus ) {
|
|
||||||
case SyncResult::Undefined:
|
|
||||||
folderMessage = tr( "Undefined Folder State" );
|
|
||||||
break;
|
|
||||||
case SyncResult::NotYetStarted:
|
|
||||||
folderMessage = tr( "The folder waits to start syncing." );
|
|
||||||
break;
|
|
||||||
case SyncResult::SyncPrepare:
|
|
||||||
folderMessage = tr( "Determining which files to sync." );
|
|
||||||
break;
|
|
||||||
case SyncResult::Unavailable:
|
|
||||||
folderMessage = tr( "Server is currently not available." );
|
|
||||||
break;
|
|
||||||
case SyncResult::SyncRunning:
|
|
||||||
folderMessage = tr("Sync is running.");
|
|
||||||
break;
|
|
||||||
case SyncResult::Success:
|
|
||||||
folderMessage = tr("Last Sync was successful.");
|
|
||||||
break;
|
|
||||||
case SyncResult::Error:
|
|
||||||
folderMessage = tr( "Syncing Error." );
|
|
||||||
break;
|
|
||||||
case SyncResult::SetupError:
|
|
||||||
folderMessage = tr( "Setup Error." );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
folderMessage = tr( "Undefined Error State." );
|
|
||||||
}
|
|
||||||
|
|
||||||
_folderMessage = folderMessage;
|
|
||||||
_lastSyncTime = result.syncTime();
|
|
||||||
|
|
||||||
if( result.errorStrings().count() ) {
|
|
||||||
_errorLabel->setVisible(true);
|
|
||||||
_errorLabel->setTextFormat(Qt::RichText);
|
|
||||||
QString errStr;
|
|
||||||
foreach( QString err, result.errorStrings() ) {
|
|
||||||
errStr.append(QString("<p>%1</p>").arg(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
_errorLabel->setText(errStr);
|
|
||||||
} else {
|
|
||||||
_errorLabel->setText(QString::null);
|
|
||||||
_errorLabel->setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
slotSetFolderMessage();
|
|
||||||
if( syncStatus == SyncResult::SyncRunning ) {
|
|
||||||
_timer.stop();
|
|
||||||
} else {
|
|
||||||
_timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
setSyncFileItems( result.syncFileItemVector() );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::slotSetFolderMessage()
|
|
||||||
{
|
|
||||||
QDateTime now = QDateTime::currentDateTime();
|
|
||||||
int secs = _lastSyncTime.secsTo(now);
|
|
||||||
|
|
||||||
if (secs < 60)
|
|
||||||
_timelabel->setText(tr("%1 (last finished %n sec. ago)", "", secs).arg(_folderMessage));
|
|
||||||
else
|
|
||||||
_timelabel->setText(tr("%1 (last finished %n min. ago)", "", secs/60).arg(_folderMessage));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::copyToClipboard()
|
|
||||||
{
|
|
||||||
QString text;
|
|
||||||
QTextStream ts(&text);
|
|
||||||
|
|
||||||
int topLevelItems = _treeWidget->topLevelItemCount();
|
|
||||||
for (int i = 0; i < topLevelItems; i++) {
|
|
||||||
QTreeWidgetItem *item = _treeWidget->topLevelItem(i);
|
|
||||||
ts << left << qSetFieldWidth(50)
|
|
||||||
<< item->data(0, Qt::DisplayRole).toString()
|
|
||||||
<< right << qSetFieldWidth(6)
|
|
||||||
<< item->data(1, Qt::DisplayRole).toString()
|
|
||||||
<< endl;
|
|
||||||
int childItems = item->childCount();
|
|
||||||
for (int j = 0; j < childItems; j++) {
|
|
||||||
QTreeWidgetItem *child =item->child(j);
|
|
||||||
ts << left << qSetFieldWidth(0) << QLatin1String(" ")
|
|
||||||
<< child->data(0,Qt::DisplayRole).toString()
|
|
||||||
<< QString::fromLatin1(" (%1)").arg(
|
|
||||||
child->data(1, Qt::DisplayRole).toString()
|
|
||||||
)
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QApplication::clipboard()->setText(text);
|
|
||||||
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::accept()
|
|
||||||
{
|
|
||||||
_timer.stop();
|
|
||||||
QDialog::accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::setSyncFileItems( const SyncFileItemVector& list )
|
|
||||||
{
|
|
||||||
_treeWidget->clear();
|
|
||||||
QStringList strings;
|
|
||||||
QFont headerFont;
|
|
||||||
headerFont.setWeight(QFont::Bold);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Synced Files"));
|
|
||||||
_syncedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_SUCCESS );
|
|
||||||
_syncedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_syncedFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("New Files"));
|
|
||||||
_newFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_NEW );
|
|
||||||
_newFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_newFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Deleted Files"));
|
|
||||||
_deletedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_DELETED );
|
|
||||||
_deletedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_deletedFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Renamed Files"));
|
|
||||||
_renamedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_RENAME);
|
|
||||||
_renamedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_renamedFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Ignored Files"));
|
|
||||||
_ignoredFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_IGNORE);
|
|
||||||
_ignoredFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_renamedFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Errors"));
|
|
||||||
_errorFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_ERROR );
|
|
||||||
_errorFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_errorFileItem);
|
|
||||||
|
|
||||||
strings.clear();
|
|
||||||
strings.append(tr("Conflicts"));
|
|
||||||
_conflictFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_CONFLICT);
|
|
||||||
_conflictFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
|
|
||||||
_treeWidget->addTopLevelItem(_conflictFileItem);
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> syncedItems;
|
|
||||||
QList<QTreeWidgetItem*> renamedItems;
|
|
||||||
QList<QTreeWidgetItem*> newItems;
|
|
||||||
QList<QTreeWidgetItem*> deletedItems;
|
|
||||||
QList<QTreeWidgetItem*> ignoredItems;
|
|
||||||
QList<QTreeWidgetItem*> conflictItems;
|
|
||||||
QList<QTreeWidgetItem*> errorItems;
|
|
||||||
|
|
||||||
quint64 overall_files = 0;
|
|
||||||
|
|
||||||
foreach( SyncFileItem item, list ) {
|
|
||||||
overall_files++;
|
|
||||||
|
|
||||||
QString dir;
|
|
||||||
QStringList str( item._file );
|
|
||||||
if( item._dir == SyncFileItem::Up ) dir = tr("Uploaded");
|
|
||||||
if( item._dir == SyncFileItem::Down ) dir = tr("Downloaded");
|
|
||||||
str << dir;
|
|
||||||
|
|
||||||
switch( item._instruction ) {
|
|
||||||
case CSYNC_INSTRUCTION_NONE:
|
|
||||||
// do nothing.
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_EVAL:
|
|
||||||
// should not happen
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_REMOVE:
|
|
||||||
case CSYNC_INSTRUCTION_DELETED:
|
|
||||||
deletedItems.append( new QTreeWidgetItem(_deletedFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_RENAME:
|
|
||||||
renamedItems.append( new QTreeWidgetItem(_renamedFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_NEW:
|
|
||||||
newItems.append( new QTreeWidgetItem(_newFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_CONFLICT:
|
|
||||||
conflictItems.append( new QTreeWidgetItem(_conflictFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_IGNORE:
|
|
||||||
ignoredItems.append( new QTreeWidgetItem(_ignoredFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_SYNC:
|
|
||||||
case CSYNC_INSTRUCTION_UPDATED:
|
|
||||||
syncedItems.append( new QTreeWidgetItem(_syncedFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_STAT_ERROR:
|
|
||||||
case CSYNC_INSTRUCTION_ERROR:
|
|
||||||
errorItems.append( new QTreeWidgetItem(_errorFileItem, str, FILE_TYPE) );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formatHeaderItem( _syncedFileItem, syncedItems );
|
|
||||||
formatHeaderItem( _newFileItem, newItems );
|
|
||||||
formatHeaderItem( _deletedFileItem, deletedItems );
|
|
||||||
formatHeaderItem( _renamedFileItem, renamedItems );
|
|
||||||
formatHeaderItem( _errorFileItem, errorItems );
|
|
||||||
formatHeaderItem( _conflictFileItem, conflictItems );
|
|
||||||
formatHeaderItem( _ignoredFileItem, ignoredItems );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileItemDialog::formatHeaderItem( QTreeWidgetItem *header, const QList<QTreeWidgetItem*>& list )
|
|
||||||
{
|
|
||||||
if( !header ) return;
|
|
||||||
|
|
||||||
header->addChildren( list );
|
|
||||||
int count = list.count();
|
|
||||||
#if LEAVE_THAT_TO_DESIGNERS
|
|
||||||
QColor col("#adc5d3");
|
|
||||||
header->setBackgroundColor(0, col);
|
|
||||||
header->setBackgroundColor(1, col);
|
|
||||||
#endif
|
|
||||||
header->setText(1, QString::number( count ));
|
|
||||||
if( count ) {
|
|
||||||
QFont font;
|
|
||||||
font.setWeight( QFont::Bold );
|
|
||||||
header->setFont(0, font);
|
|
||||||
header->setFont(1, font);
|
|
||||||
header->setExpanded(true);
|
|
||||||
} else {
|
|
||||||
header->setExpanded(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ class FileUtils
|
|||||||
public:
|
public:
|
||||||
enum SubFolderListOption {
|
enum SubFolderListOption {
|
||||||
SubFolderNoOptions = 0x0,
|
SubFolderNoOptions = 0x0,
|
||||||
SubFolderRecursive = 0x1,
|
SubFolderRecursive = 0x1
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(SubFolderListOptions, SubFolderListOption)
|
Q_DECLARE_FLAGS(SubFolderListOptions, SubFolderListOption)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,66 +19,108 @@
|
|||||||
#include "mirall/folderwatcher.h"
|
#include "mirall/folderwatcher.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/syncresult.h"
|
#include "mirall/syncresult.h"
|
||||||
|
#include "mirall/logger.h"
|
||||||
|
#include "mirall/owncloudinfo.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "folderman.h"
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
|
void csyncLogCatcher(CSYNC */*ctx*/,
|
||||||
|
int /*verbosity*/,
|
||||||
|
const char */*function*/,
|
||||||
|
const char *buffer,
|
||||||
|
void */*userdata*/)
|
||||||
|
{
|
||||||
|
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||||
|
}
|
||||||
|
|
||||||
Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent)
|
Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent)
|
||||||
_errorCount(0),
|
, _path(path)
|
||||||
_path(path),
|
, _secondPath(secondPath)
|
||||||
_secondPath(secondPath),
|
, _alias(alias)
|
||||||
_pollTimer(new QTimer(this)),
|
, _enabled(true)
|
||||||
_alias(alias),
|
, _thread(0)
|
||||||
_onlyOnlineEnabled(false),
|
, _csync(0)
|
||||||
_onlyThisLANEnabled(false),
|
, _csyncError(false)
|
||||||
_online(false),
|
, _csyncUnavail(false)
|
||||||
_enabled(true)
|
, _csync_ctx(0)
|
||||||
{
|
{
|
||||||
qsrand(QTime::currentTime().msec());
|
qsrand(QTime::currentTime().msec());
|
||||||
MirallConfigFile cfgFile;
|
_timeSinceLastSync.start();
|
||||||
|
|
||||||
_pollTimer->setSingleShot(true);
|
_watcher = new FolderWatcher(path, this);
|
||||||
int polltime = cfgFile.remotePollInterval()- 2000 + (int)( 4000.0*qrand()/(RAND_MAX+1.0));
|
|
||||||
qDebug() << "setting remote poll timer interval to" << polltime << "msec for folder " << alias;
|
|
||||||
_pollTimer->setInterval( polltime );
|
|
||||||
|
|
||||||
QObject::connect(_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
|
|
||||||
_pollTimer->start();
|
|
||||||
|
|
||||||
_watcher = new Mirall::FolderWatcher(path, this);
|
|
||||||
|
|
||||||
MirallConfigFile cfg;
|
MirallConfigFile cfg;
|
||||||
|
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::SystemScope) );
|
||||||
_watcher->setIgnoreListFile( cfg.excludeFile() );
|
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::UserScope) );
|
||||||
|
|
||||||
QObject::connect(_watcher, SIGNAL(folderChanged(const QStringList &)),
|
QObject::connect(_watcher, SIGNAL(folderChanged(const QStringList &)),
|
||||||
SLOT(slotChanged(const QStringList &)));
|
SLOT(slotChanged(const QStringList &)));
|
||||||
QObject::connect(this, SIGNAL(syncStarted()),
|
|
||||||
SLOT(slotSyncStarted()));
|
|
||||||
QObject::connect(this, SIGNAL(syncFinished(const SyncResult &)),
|
|
||||||
SLOT(slotSyncFinished(const SyncResult &)));
|
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
_online = _networkMgr.isOnline();
|
|
||||||
QObject::connect(&_networkMgr, SIGNAL(onlineStateChanged(bool)), SLOT(slotOnlineChanged(bool)));
|
|
||||||
#else
|
|
||||||
_online = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||||
|
|
||||||
// check if the local path exists
|
// check if the local path exists
|
||||||
checkLocalPath();
|
checkLocalPath();
|
||||||
|
|
||||||
|
int polltime = cfg.remotePollInterval();
|
||||||
|
qDebug() << "setting remote poll timer interval to" << polltime << "msec";
|
||||||
|
_pollTimer.setInterval( polltime );
|
||||||
|
QObject::connect(&_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
|
||||||
|
_pollTimer.start();
|
||||||
|
|
||||||
|
_syncResult.setFolder(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Folder::init()
|
||||||
|
{
|
||||||
|
QString url = Utility::toCSyncScheme(ownCloudInfo::instance()->webdavUrl() + secondPath());
|
||||||
|
QString localpath = path();
|
||||||
|
|
||||||
|
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
|
||||||
|
qDebug() << "Unable to create csync-context!";
|
||||||
|
slotCSyncError(tr("Unable to create csync-context"));
|
||||||
|
_csync_ctx = 0;
|
||||||
|
} else {
|
||||||
|
csync_set_log_callback( _csync_ctx, csyncLogCatcher );
|
||||||
|
csync_set_log_verbosity(_csync_ctx, 11);
|
||||||
|
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
|
||||||
|
|
||||||
|
csync_enable_conflictcopys(_csync_ctx);
|
||||||
|
setIgnoredFiles();
|
||||||
|
cfgFile.getCredentials()->syncContextPreInit(_csync_ctx);
|
||||||
|
|
||||||
|
if( csync_init( _csync_ctx ) < 0 ) {
|
||||||
|
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
|
||||||
|
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
|
||||||
|
csync_destroy(_csync_ctx);
|
||||||
|
_csync_ctx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _csync_ctx;
|
||||||
|
}
|
||||||
Folder::~Folder()
|
Folder::~Folder()
|
||||||
{
|
{
|
||||||
|
if( _thread ) {
|
||||||
|
_thread->quit();
|
||||||
|
csync_request_abort(_csync_ctx);
|
||||||
|
_thread->wait();
|
||||||
|
}
|
||||||
|
delete _csync;
|
||||||
|
// Destroy csync here.
|
||||||
|
csync_destroy(_csync_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::checkLocalPath()
|
void Folder::checkLocalPath()
|
||||||
@@ -129,6 +173,11 @@ QString Folder::path() const
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Folder::isBusy() const
|
||||||
|
{
|
||||||
|
return ( _thread && _thread->isRunning() );
|
||||||
|
}
|
||||||
|
|
||||||
QString Folder::secondPath() const
|
QString Folder::secondPath() const
|
||||||
{
|
{
|
||||||
return _secondPath;
|
return _secondPath;
|
||||||
@@ -148,9 +197,6 @@ void Folder::setSyncEnabled( bool doit )
|
|||||||
{
|
{
|
||||||
_enabled = doit;
|
_enabled = doit;
|
||||||
_watcher->setEventsEnabled( doit );
|
_watcher->setEventsEnabled( doit );
|
||||||
if( doit && ! _pollTimer->isActive() ) {
|
|
||||||
_pollTimer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "setSyncEnabled - ############################ " << doit;
|
qDebug() << "setSyncEnabled - ############################ " << doit;
|
||||||
if( doit ) {
|
if( doit ) {
|
||||||
@@ -163,85 +209,22 @@ void Folder::setSyncEnabled( bool doit )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Folder::onlyOnlineEnabled() const
|
|
||||||
{
|
|
||||||
return _onlyOnlineEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setOnlyOnlineEnabled(bool enabled)
|
|
||||||
{
|
|
||||||
_onlyOnlineEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Folder::onlyThisLANEnabled() const
|
|
||||||
{
|
|
||||||
return _onlyThisLANEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setOnlyThisLANEnabled(bool enabled)
|
|
||||||
{
|
|
||||||
_onlyThisLANEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Folder::pollInterval() const
|
|
||||||
{
|
|
||||||
return _pollTimer->interval();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setSyncState(SyncResult::Status state)
|
void Folder::setSyncState(SyncResult::Status state)
|
||||||
{
|
{
|
||||||
_syncResult.setStatus(state);
|
_syncResult.setStatus(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::setPollInterval(int milliseconds)
|
|
||||||
{
|
|
||||||
_pollTimer->setInterval( milliseconds );
|
|
||||||
}
|
|
||||||
|
|
||||||
int Folder::errorCount()
|
|
||||||
{
|
|
||||||
return _errorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::resetErrorCount()
|
|
||||||
{
|
|
||||||
_errorCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::incrementErrorCount()
|
|
||||||
{
|
|
||||||
// if the error count gets higher than three, the interval timer
|
|
||||||
// of the watcher is doubled.
|
|
||||||
_errorCount++;
|
|
||||||
if( _errorCount > 1 ) {
|
|
||||||
int interval = _watcher->eventInterval();
|
|
||||||
int newInt = 2*interval;
|
|
||||||
qDebug() << "Set new watcher interval to " << newInt;
|
|
||||||
_watcher->setEventInterval( newInt );
|
|
||||||
_errorCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncResult Folder::syncResult() const
|
SyncResult Folder::syncResult() const
|
||||||
{
|
{
|
||||||
return _syncResult;
|
return _syncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::evaluateSync(const QStringList &pathList)
|
void Folder::evaluateSync(const QStringList &/*pathList*/)
|
||||||
{
|
{
|
||||||
if( !_enabled ) {
|
if( !_enabled ) {
|
||||||
qDebug() << "*" << alias() << "sync skipped, disabled!";
|
qDebug() << "*" << alias() << "sync skipped, disabled!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_online && onlyOnlineEnabled()) {
|
|
||||||
qDebug() << "*" << alias() << "sync skipped, not online";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop the poll timer here. Its started again in the slot of
|
|
||||||
// sync finished.
|
|
||||||
qDebug() << "* " << alias() << "Poll timer disabled";
|
|
||||||
_pollTimer->stop();
|
|
||||||
|
|
||||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||||
emit scheduleToSync( alias() );
|
emit scheduleToSync( alias() );
|
||||||
@@ -250,15 +233,36 @@ void Folder::evaluateSync(const QStringList &pathList)
|
|||||||
|
|
||||||
void Folder::slotPollTimerTimeout()
|
void Folder::slotPollTimerTimeout()
|
||||||
{
|
{
|
||||||
qDebug() << "* Polling" << alias() << "for changes. Ignoring all pending events until now";
|
qDebug() << "* Polling" << alias() << "for changes. (time since next sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
|
||||||
_watcher->clearPendingEvents();
|
|
||||||
evaluateSync(QStringList());
|
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval()) {
|
||||||
|
qDebug() << "* Force Sync now";
|
||||||
|
evaluateSync(QStringList());
|
||||||
|
} else {
|
||||||
|
RequestEtagJob* job = new RequestEtagJob(secondPath(), this);
|
||||||
|
// check if the etag is different
|
||||||
|
QObject::connect(job, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
|
||||||
|
QObject::connect(job, SIGNAL(networkError()), this, SLOT(slotNetworkUnavailable()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotOnlineChanged(bool online)
|
void Folder::etagRetreived(const QString& etag)
|
||||||
{
|
{
|
||||||
qDebug() << "* " << alias() << "is" << (online ? "now online" : "no longer online");
|
qDebug() << "* Compare etag with previous etag: " << (_lastEtag != etag);
|
||||||
_online = online;
|
|
||||||
|
// re-enable sync if it was disabled because network was down
|
||||||
|
FolderMan::instance()->setSyncEnabled(true);
|
||||||
|
|
||||||
|
if (_lastEtag != etag) {
|
||||||
|
_lastEtag = etag;
|
||||||
|
evaluateSync(QStringList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotNetworkUnavailable()
|
||||||
|
{
|
||||||
|
_syncResult.setStatus(SyncResult::Unavailable);
|
||||||
|
emit syncStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotChanged(const QStringList &pathList)
|
void Folder::slotChanged(const QStringList &pathList)
|
||||||
@@ -267,36 +271,100 @@ void Folder::slotChanged(const QStringList &pathList)
|
|||||||
evaluateSync(pathList);
|
evaluateSync(pathList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotSyncStarted()
|
void Folder::bubbleUpSyncResult()
|
||||||
{
|
{
|
||||||
// disable events until syncing is done
|
// count new, removed and updated items
|
||||||
_watcher->setEventsEnabled(false);
|
int newItems = 0;
|
||||||
}
|
int removedItems = 0;
|
||||||
|
int updatedItems = 0;
|
||||||
|
int ignoredItems = 0;
|
||||||
|
|
||||||
void Folder::slotSyncFinished(const SyncResult &result)
|
SyncFileItem firstItemNew;
|
||||||
{
|
SyncFileItem firstItemDeleted;
|
||||||
_watcher->setEventsEnabledDelayed(2000);
|
SyncFileItem firstItemUpdated;
|
||||||
|
|
||||||
qDebug() << "OO folder slotSyncFinished: result: " << int(result.status());
|
foreach (const SyncFileItem &item, _syncResult.syncFileItemVector() ) {
|
||||||
emit syncStateChange();
|
if( item._instruction == CSYNC_INSTRUCTION_ERROR ) {
|
||||||
|
slotCSyncError( tr("File %1: %2").arg(item._file).arg(item._errorString) );
|
||||||
|
} else {
|
||||||
|
if (item._dir == SyncFileItem::Down) {
|
||||||
|
switch (item._instruction) {
|
||||||
|
case CSYNC_INSTRUCTION_NEW:
|
||||||
|
newItems++;
|
||||||
|
if (firstItemNew.isEmpty())
|
||||||
|
firstItemNew = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_REMOVE:
|
||||||
|
removedItems++;
|
||||||
|
if (firstItemDeleted.isEmpty())
|
||||||
|
firstItemDeleted = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_UPDATED:
|
||||||
|
updatedItems++;
|
||||||
|
if (firstItemUpdated.isEmpty())
|
||||||
|
firstItemUpdated = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_ERROR:
|
||||||
|
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// nothing.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if( item._dir == SyncFileItem::None ) { // ignored files counting.
|
||||||
|
if( item._instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||||
|
ignoredItems++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reenable the poll timer if folder is sync enabled
|
_syncResult.setWarnCount(ignoredItems);
|
||||||
if( syncEnabled() ) {
|
|
||||||
qDebug() << "* " << alias() << "Poll timer enabled with " << _pollTimer->interval() << "milliseconds";
|
Logger *logger = Logger::instance();
|
||||||
_pollTimer->start();
|
|
||||||
} else {
|
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
||||||
qDebug() << "* Not enabling poll timer for " << alias();
|
if (newItems > 0) {
|
||||||
_pollTimer->stop();
|
QString file = QDir::toNativeSeparators(firstItemNew._file);
|
||||||
|
if (newItems == 1)
|
||||||
|
logger->postGuiLog(tr("New file available"), tr("'%1' has been synced to this machine.").arg(file));
|
||||||
|
else
|
||||||
|
logger->postGuiLog(tr("New files available"), tr("'%1' and %n other file(s) have been synced to this machine.",
|
||||||
|
"", newItems-1).arg(file));
|
||||||
|
}
|
||||||
|
if (removedItems > 0) {
|
||||||
|
QString file = QDir::toNativeSeparators(firstItemDeleted._file);
|
||||||
|
if (removedItems == 1)
|
||||||
|
logger->postGuiLog(tr("File removed"), tr("'%1' has been removed.").arg(file));
|
||||||
|
else
|
||||||
|
logger->postGuiLog(tr("Files removed"), tr("'%1' and %n other file(s) have been removed.",
|
||||||
|
"", removedItems-1).arg(file));
|
||||||
|
}
|
||||||
|
if (updatedItems > 0) {
|
||||||
|
QString file = QDir::toNativeSeparators(firstItemUpdated._file);
|
||||||
|
if (updatedItems == 1)
|
||||||
|
logger->postGuiLog(tr("File updated"), tr("'%1' has been updated.").arg(file));
|
||||||
|
else
|
||||||
|
logger->postGuiLog(tr("Files updated"), tr("'%1' and %n other file(s) have been updated.",
|
||||||
|
"", updatedItems-1).arg(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotLocalPathChanged( const QString& dir )
|
void Folder::slotLocalPathChanged( const QString& dir )
|
||||||
{
|
{
|
||||||
QDir notifiedDir(dir);
|
QDir notifiedDir(dir);
|
||||||
QDir localPath(_path );
|
QDir localPath( path() );
|
||||||
|
|
||||||
if( notifiedDir == localPath ) {
|
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
|
||||||
if( !localPath.exists() ) {
|
if( !localPath.exists() ) {
|
||||||
|
qDebug() << "XXXXXXX The sync folder root was removed!!";
|
||||||
|
if( _thread && _thread->isRunning() ) {
|
||||||
|
qDebug() << "CSync currently running, set wipe flag!!";
|
||||||
|
} else {
|
||||||
|
qDebug() << "CSync not running, wipe it now!!";
|
||||||
|
wipe();
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "ALARM: The local path was DELETED!";
|
qDebug() << "ALARM: The local path was DELETED!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,20 +380,303 @@ QString Folder::configFile()
|
|||||||
return _configFile;
|
return _configFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::setBackend( const QString& b )
|
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||||
{
|
{
|
||||||
_backend = b;
|
_syncResult.setSyncFileItemVector(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Folder::backend() const
|
void Folder::slotCatchWatcherError(const QString& error)
|
||||||
{
|
{
|
||||||
return _backend;
|
Logger::instance()->postGuiLog(tr("Error"), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::slotTerminateSync()
|
||||||
|
{
|
||||||
|
qDebug() << "folder " << alias() << " Terminating!";
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
QString configDir = cfg.configPath();
|
||||||
|
qDebug() << "csync's Config Dir: " << configDir;
|
||||||
|
|
||||||
|
if( _thread && _csync ) {
|
||||||
|
csync_request_abort(_csync_ctx);
|
||||||
|
_thread->quit();
|
||||||
|
_thread->wait();
|
||||||
|
_csync->deleteLater();
|
||||||
|
delete _thread;
|
||||||
|
_csync = 0;
|
||||||
|
_thread = 0;
|
||||||
|
csync_resume(_csync_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ! configDir.isEmpty() ) {
|
||||||
|
QFile file( configDir + QLatin1String("/lock"));
|
||||||
|
if( file.exists() ) {
|
||||||
|
qDebug() << "After termination, lock file exists and gets removed.";
|
||||||
|
file.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_errors.append( tr("The CSync thread terminated.") );
|
||||||
|
_csyncError = true;
|
||||||
|
qDebug() << "-> CSync Terminated!";
|
||||||
|
slotCSyncFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This removes the csync File database if the sync folder definition is removed
|
||||||
|
// permanentely. This is needed to provide a clean startup again in case another
|
||||||
|
// local folder is synced to the same ownCloud.
|
||||||
|
// See http://bugs.owncloud.org/thebuggenie/owncloud/issues/oc-788
|
||||||
void Folder::wipe()
|
void Folder::wipe()
|
||||||
{
|
{
|
||||||
|
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
|
||||||
|
|
||||||
|
QFile file(stateDbFile);
|
||||||
|
if( file.exists() ) {
|
||||||
|
if( !file.remove()) {
|
||||||
|
qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile;
|
||||||
|
} else {
|
||||||
|
qDebug() << "wipe: Removed csync StateDB " << stateDbFile;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "WRN: statedb is empty, can not remove.";
|
||||||
|
}
|
||||||
|
// Check if the tmp database file also exists
|
||||||
|
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
|
||||||
|
QFile ctmpFile( ctmpName );
|
||||||
|
if( ctmpFile.exists() ) {
|
||||||
|
ctmpFile.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::setIgnoredFiles()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
csync_clear_exclude_list( _csync_ctx );
|
||||||
|
QString excludeList = cfgFile.excludeFile( MirallConfigFile::SystemScope );
|
||||||
|
if( !excludeList.isEmpty() ) {
|
||||||
|
qDebug() << "==== added system ignore list to csync:" << excludeList.toUtf8();
|
||||||
|
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
|
||||||
|
}
|
||||||
|
excludeList = cfgFile.excludeFile( MirallConfigFile::UserScope );
|
||||||
|
if( !excludeList.isEmpty() ) {
|
||||||
|
qDebug() << "==== added user defined ignore list to csync:" << excludeList.toUtf8();
|
||||||
|
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::setProxy()
|
||||||
|
{
|
||||||
|
if( _csync_ctx ) {
|
||||||
|
/* Store proxy */
|
||||||
|
QUrl proxyUrl(ownCloudInfo::instance()->webdavUrl());
|
||||||
|
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(proxyUrl);
|
||||||
|
// We set at least one in Application
|
||||||
|
Q_ASSERT(proxies.count() > 0);
|
||||||
|
QNetworkProxy proxy = proxies.first();
|
||||||
|
if (proxy.type() == QNetworkProxy::NoProxy) {
|
||||||
|
qDebug() << "Passing NO proxy to csync for" << proxyUrl;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type()
|
||||||
|
<< " to csync for" << proxyUrl;
|
||||||
|
}
|
||||||
|
int proxyPort = proxy.port();
|
||||||
|
|
||||||
|
csync_set_module_property(_csync_ctx, "proxy_type", (char*) proxyTypeToCStr(proxy.type()) );
|
||||||
|
csync_set_module_property(_csync_ctx, "proxy_host", proxy.hostName().toUtf8().data() );
|
||||||
|
csync_set_module_property(_csync_ctx, "proxy_port", &proxyPort );
|
||||||
|
csync_set_module_property(_csync_ctx, "proxy_user", proxy.user().toUtf8().data() );
|
||||||
|
csync_set_module_property(_csync_ctx, "proxy_pwd" , proxy.password().toUtf8().data() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* Folder::proxyTypeToCStr(QNetworkProxy::ProxyType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case QNetworkProxy::NoProxy:
|
||||||
|
return "NoProxy";
|
||||||
|
case QNetworkProxy::DefaultProxy:
|
||||||
|
return "DefaultProxy";
|
||||||
|
case QNetworkProxy::Socks5Proxy:
|
||||||
|
return "Socks5Proxy";
|
||||||
|
case QNetworkProxy::HttpProxy:
|
||||||
|
return "HttpProxy";
|
||||||
|
case QNetworkProxy::HttpCachingProxy:
|
||||||
|
return "HttpCachingProxy";
|
||||||
|
case QNetworkProxy::FtpCachingProxy:
|
||||||
|
return "FtpCachingProxy";
|
||||||
|
default:
|
||||||
|
return "NoProxy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::startSync(const QStringList &pathList)
|
||||||
|
{
|
||||||
|
Q_UNUSED(pathList)
|
||||||
|
if (!_csync_ctx) {
|
||||||
|
// no _csync_ctx yet, initialize it.
|
||||||
|
init();
|
||||||
|
setProxy();
|
||||||
|
|
||||||
|
if (!_csync_ctx) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "init failed.";
|
||||||
|
// the error should already be set
|
||||||
|
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_thread && _thread->isRunning()) {
|
||||||
|
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_thread)
|
||||||
|
_thread->quit();
|
||||||
|
delete _csync;
|
||||||
|
delete _thread;
|
||||||
|
_errors.clear();
|
||||||
|
_csyncError = false;
|
||||||
|
_csyncUnavail = false;
|
||||||
|
|
||||||
|
_syncResult.clearErrors();
|
||||||
|
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||||
|
emit syncStateChange();
|
||||||
|
|
||||||
|
|
||||||
|
qDebug() << "*** Start syncing";
|
||||||
|
_thread = new QThread(this);
|
||||||
|
_thread->setPriority(QThread::LowPriority);
|
||||||
|
setIgnoredFiles();
|
||||||
|
_csync = new CSyncThread( _csync_ctx );
|
||||||
|
_csync->moveToThread(_thread);
|
||||||
|
|
||||||
|
|
||||||
|
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||||
|
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||||
|
|
||||||
|
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||||
|
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
connect(_csync, SIGNAL(started()), SLOT(slotCSyncStarted()), Qt::QueuedConnection);
|
||||||
|
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
||||||
|
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
|
||||||
|
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
//blocking connection so the message box happens in this thread, but block the csync thread.
|
||||||
|
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
|
||||||
|
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
|
||||||
|
connect(_csync, SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
|
||||||
|
|
||||||
|
_thread->start();
|
||||||
|
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// disable events until syncing is done
|
||||||
|
_watcher->setEventsEnabled(false);
|
||||||
|
_pollTimer.stop();
|
||||||
|
emit syncStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotCSyncError(const QString& err)
|
||||||
|
{
|
||||||
|
_errors.append( err );
|
||||||
|
_csyncError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotCSyncStarted()
|
||||||
|
{
|
||||||
|
qDebug() << " * csync thread started";
|
||||||
|
_syncResult.setStatus(SyncResult::SyncRunning);
|
||||||
|
emit syncStateChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotCsyncUnavailable()
|
||||||
|
{
|
||||||
|
_csyncUnavail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotCSyncFinished()
|
||||||
|
{
|
||||||
|
qDebug() << "-> CSync Finished slot with error " << _csyncError;
|
||||||
|
_watcher->setEventsEnabledDelayed(2000);
|
||||||
|
_pollTimer.start();
|
||||||
|
_timeSinceLastSync.restart();
|
||||||
|
|
||||||
|
bubbleUpSyncResult();
|
||||||
|
|
||||||
|
if (_csyncError) {
|
||||||
|
_syncResult.setStatus(SyncResult::Error);
|
||||||
|
qDebug() << " ** error Strings: " << _errors;
|
||||||
|
_syncResult.setErrorStrings( _errors );
|
||||||
|
qDebug() << " * owncloud csync thread finished with error";
|
||||||
|
} else if (_csyncUnavail) {
|
||||||
|
_syncResult.setStatus(SyncResult::Unavailable);
|
||||||
|
} else if( _syncResult.warnCount() > 0 ) {
|
||||||
|
// there have been warnings on the way.
|
||||||
|
_syncResult.setStatus(SyncResult::Problem);
|
||||||
|
} else {
|
||||||
|
_syncResult.setStatus(SyncResult::Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _thread && _thread->isRunning() ) {
|
||||||
|
_thread->quit();
|
||||||
|
}
|
||||||
|
emit syncStateChange();
|
||||||
|
ownCloudInfo::instance()->getQuotaRequest("/");
|
||||||
|
emit syncFinished( _syncResult );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotTransmissionProgress(const Progress::Info& progress)
|
||||||
|
{
|
||||||
|
Progress::Info newInfo = progress;
|
||||||
|
newInfo.folder = alias();
|
||||||
|
|
||||||
|
if(newInfo.current_file.startsWith(QLatin1String("ownclouds://")) ||
|
||||||
|
newInfo.current_file.startsWith(QLatin1String("owncloud://")) ) {
|
||||||
|
// rip off the whole ownCloud URL.
|
||||||
|
QString remotePathUrl = ownCloudInfo::instance()->webdavUrl() + secondPath();
|
||||||
|
newInfo.current_file.remove(Utility::toCSyncScheme(remotePathUrl));
|
||||||
|
}
|
||||||
|
QString localPath = path();
|
||||||
|
if( newInfo.current_file.startsWith(localPath) ) {
|
||||||
|
// remove the local dir.
|
||||||
|
newInfo.current_file = newInfo.current_file.right( newInfo.current_file.length() - localPath.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember problems happening to set the correct Sync status in slot slotCSyncFinished.
|
||||||
|
if( newInfo.kind == Progress::StartSync ) {
|
||||||
|
_syncResult.setWarnCount(0);
|
||||||
|
}
|
||||||
|
if( newInfo.kind == Progress::Error ) {
|
||||||
|
_syncResult.setWarnCount( _syncResult.warnCount()+1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
||||||
|
{
|
||||||
|
QString msg = direction == SyncFileItem::Down ?
|
||||||
|
tr("This sync would remove all the files in the local sync folder '%1'.\n"
|
||||||
|
"If you or your administrator have reset your account on the server, choose "
|
||||||
|
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
|
||||||
|
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
||||||
|
"This might be because the folder was silently reconfigured, or that all "
|
||||||
|
"the file were manually removed.\n"
|
||||||
|
"Are you sure you want to perform this operation?");
|
||||||
|
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||||
|
msg.arg(alias()));
|
||||||
|
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||||
|
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
|
||||||
|
if (msgBox.exec() == -1) {
|
||||||
|
*cancel = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*cancel = msgBox.clickedButton() == keepBtn;
|
||||||
|
if (*cancel) {
|
||||||
|
wipe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Mirall
|
} // namespace Mirall
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -15,38 +17,61 @@
|
|||||||
#ifndef MIRALL_FOLDER_H
|
#ifndef MIRALL_FOLDER_H
|
||||||
#define MIRALL_FOLDER_H
|
#define MIRALL_FOLDER_H
|
||||||
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
#include <QNetworkConfigurationManager>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mirall/syncresult.h"
|
#include "mirall/syncresult.h"
|
||||||
|
#include "mirall/progressdispatcher.h"
|
||||||
|
#include "mirall/csyncthread.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkProxy>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <qelapsedtimer.h>
|
||||||
|
|
||||||
class QAction;
|
|
||||||
class QIcon;
|
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
|
class QThread;
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
class FolderWatcher;
|
class FolderWatcher;
|
||||||
|
|
||||||
|
typedef enum SyncFileStatus_s {
|
||||||
|
STATUS_NONE,
|
||||||
|
STATUS_EVAL,
|
||||||
|
STATUS_REMOVE,
|
||||||
|
STATUS_RENAME,
|
||||||
|
STATUS_NEW,
|
||||||
|
STATUS_CONFLICT,
|
||||||
|
STATUS_IGNORE,
|
||||||
|
STATUS_SYNC,
|
||||||
|
STATUS_STAT_ERROR,
|
||||||
|
STATUS_ERROR,
|
||||||
|
STATUS_UPDATED
|
||||||
|
} SyncFileStatus;
|
||||||
|
|
||||||
class Folder : public QObject
|
class Folder : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
|
friend class FolderMan;
|
||||||
Folder(const QString&, const QString&, const QString& , QObject*parent = 0L);
|
Folder(const QString&, const QString&, const QString& , QObject*parent = 0L);
|
||||||
virtual ~Folder();
|
|
||||||
|
public:
|
||||||
|
~Folder();
|
||||||
|
|
||||||
typedef QHash<QString, Folder*> Map;
|
typedef QHash<QString, Folder*> Map;
|
||||||
typedef QHashIterator<QString, Folder*> MapIterator;
|
typedef QHashIterator<QString, Folder*> MapIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get status about a single file.
|
||||||
|
*/
|
||||||
|
SyncFileStatus fileStatus( const QString& );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* alias or nickname
|
* alias or nickname
|
||||||
*/
|
*/
|
||||||
@@ -56,12 +81,16 @@ public:
|
|||||||
* local folder path
|
* local folder path
|
||||||
*/
|
*/
|
||||||
QString path() const;
|
QString path() const;
|
||||||
virtual QString secondPath() const;
|
/**
|
||||||
|
* remote folder path
|
||||||
|
*/
|
||||||
|
QString secondPath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* local folder path with native separators
|
* local folder path with native separators
|
||||||
*/
|
*/
|
||||||
QString nativePath() const;
|
QString nativePath() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch sync on or off
|
* switch sync on or off
|
||||||
* If the sync is switched off, the startSync method is not going to
|
* If the sync is switched off, the startSync method is not going to
|
||||||
@@ -71,69 +100,17 @@ public:
|
|||||||
|
|
||||||
bool syncEnabled() const;
|
bool syncEnabled() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a sync operation
|
|
||||||
*
|
|
||||||
* If the list of changed files is known, it is passed.
|
|
||||||
*
|
|
||||||
* If the list of changed files is empty, the folder
|
|
||||||
* implementation should figure it by itself of
|
|
||||||
* perform a full scan of changes
|
|
||||||
*/
|
|
||||||
virtual void startSync(const QStringList &pathList) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the folder is busy and can't initiate
|
* True if the folder is busy and can't initiate
|
||||||
* a synchronization
|
* a synchronization
|
||||||
*/
|
*/
|
||||||
virtual bool isBusy() const = 0;
|
virtual bool isBusy() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* only sync when online in the network
|
|
||||||
*/
|
|
||||||
bool onlyOnlineEnabled() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see onlyOnlineEnabled
|
|
||||||
*/
|
|
||||||
void setOnlyOnlineEnabled(bool enabled);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* only sync when online in the same LAN
|
|
||||||
* as the one used during setup
|
|
||||||
*/
|
|
||||||
bool onlyThisLANEnabled() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see onlyThisLANEnabled
|
|
||||||
*/
|
|
||||||
void setOnlyThisLANEnabled(bool enabled);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* error counter, stop syncing after the counter reaches a certain
|
|
||||||
* number.
|
|
||||||
*/
|
|
||||||
int errorCount();
|
|
||||||
|
|
||||||
void resetErrorCount();
|
|
||||||
|
|
||||||
void incrementErrorCount();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the last sync result with error message and status
|
* return the last sync result with error message and status
|
||||||
*/
|
*/
|
||||||
SyncResult syncResult() const;
|
SyncResult syncResult() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* set the backend description string.
|
|
||||||
*/
|
|
||||||
void setBackend( const QString& );
|
|
||||||
/**
|
|
||||||
* get the backend description string.
|
|
||||||
*/
|
|
||||||
QString backend() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the config file name.
|
* set the config file name.
|
||||||
*/
|
*/
|
||||||
@@ -145,9 +122,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void wipe();
|
virtual void wipe();
|
||||||
|
|
||||||
QIcon icon( int size ) const;
|
|
||||||
QTimer *_pollTimer;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void syncStateChange();
|
void syncStateChange();
|
||||||
void syncStarted();
|
void syncStarted();
|
||||||
@@ -155,7 +129,6 @@ signals:
|
|||||||
void scheduleToSync( const QString& );
|
void scheduleToSync( const QString& );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotSyncFinished(const SyncResult &);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -165,48 +138,47 @@ public slots:
|
|||||||
/**
|
/**
|
||||||
* terminate the current sync run
|
* terminate the current sync run
|
||||||
*/
|
*/
|
||||||
virtual void slotTerminateSync() = 0;
|
void slotTerminateSync();
|
||||||
|
|
||||||
|
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets minimum amounts of milliseconds that will separate
|
* Starts a sync operation
|
||||||
* poll intervals
|
*
|
||||||
|
* If the list of changed files is known, it is passed.
|
||||||
*/
|
*/
|
||||||
void setPollInterval( int );
|
void startSync(const QStringList &pathList = QStringList());
|
||||||
|
|
||||||
/**
|
private slots:
|
||||||
* If folder is network-based, reimplement to react to proxy changes
|
void slotCSyncStarted();
|
||||||
*/
|
void slotCSyncError(const QString& );
|
||||||
virtual void setProxy() {}
|
void slotCsyncUnavailable();
|
||||||
|
void slotCSyncFinished();
|
||||||
|
|
||||||
protected:
|
void slotTransmissionProgress(const Progress::Info& progress);
|
||||||
/**
|
|
||||||
* The minimum amounts of seconds to wait before
|
|
||||||
* doing a full sync to see if the remote changed
|
|
||||||
*/
|
|
||||||
int pollInterval() const;
|
|
||||||
void setSyncState(SyncResult::Status state);
|
|
||||||
|
|
||||||
FolderWatcher *_watcher;
|
|
||||||
int _errorCount;
|
|
||||||
SyncResult _syncResult;
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
void slotOnlineChanged(bool online);
|
|
||||||
|
|
||||||
void slotPollTimerTimeout();
|
void slotPollTimerTimeout();
|
||||||
|
void etagRetreived(const QString &);
|
||||||
/* called when the watcher detect a list of changed
|
void slotNetworkUnavailable();
|
||||||
paths */
|
|
||||||
|
|
||||||
void slotSyncStarted();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered by a file system watcher on the local sync dir
|
* Triggered by a file system watcher on the local sync dir
|
||||||
*/
|
*/
|
||||||
virtual void slotLocalPathChanged( const QString& );
|
void slotLocalPathChanged( const QString& );
|
||||||
|
void slotThreadTreeWalkResult(const SyncFileItemVector& );
|
||||||
|
void slotCatchWatcherError( const QString& );
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
void setSyncState(SyncResult::Status state);
|
||||||
|
|
||||||
|
void setIgnoredFiles();
|
||||||
|
void setProxy();
|
||||||
|
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
||||||
|
|
||||||
|
void bubbleUpSyncResult();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a sync (calling startSync)
|
* Starts a sync (calling startSync)
|
||||||
@@ -214,23 +186,28 @@ private:
|
|||||||
*/
|
*/
|
||||||
void evaluateSync(const QStringList &pathList);
|
void evaluateSync(const QStringList &pathList);
|
||||||
|
|
||||||
virtual void checkLocalPath();
|
void checkLocalPath();
|
||||||
|
|
||||||
QString _path;
|
QString _path;
|
||||||
QString _secondPath;
|
QString _secondPath;
|
||||||
QString _alias;
|
QString _alias;
|
||||||
bool _onlyOnlineEnabled;
|
|
||||||
bool _onlyThisLANEnabled;
|
|
||||||
QString _configFile;
|
QString _configFile;
|
||||||
|
|
||||||
QFileSystemWatcher *_pathWatcher;
|
QFileSystemWatcher *_pathWatcher;
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
QNetworkConfigurationManager _networkMgr;
|
|
||||||
#endif
|
|
||||||
bool _online;
|
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
QString _backend;
|
FolderWatcher *_watcher;
|
||||||
|
SyncResult _syncResult;
|
||||||
|
QThread *_thread;
|
||||||
|
CSyncThread *_csync;
|
||||||
|
QStringList _errors;
|
||||||
|
bool _csyncError;
|
||||||
|
bool _csyncUnavail;
|
||||||
|
bool _wipeDb;
|
||||||
|
Progress::Kind _progressKind;
|
||||||
|
QTimer _pollTimer;
|
||||||
|
QString _lastEtag;
|
||||||
|
QElapsedTimer _timeSinceLastSync;
|
||||||
|
|
||||||
|
CSYNC *_csync_ctx;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,11 @@
|
|||||||
|
|
||||||
#include "mirall/folderman.h"
|
#include "mirall/folderman.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/owncloudfolder.h"
|
#include "mirall/folder.h"
|
||||||
#include "mirall/syncresult.h"
|
#include "mirall/syncresult.h"
|
||||||
#include "mirall/inotify.h"
|
#include "mirall/inotify.h"
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
|
#include "owncloudinfo.h"
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
@@ -32,6 +33,8 @@
|
|||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
|
FolderMan* FolderMan::_instance = 0;
|
||||||
|
|
||||||
FolderMan::FolderMan(QObject *parent) :
|
FolderMan::FolderMan(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_syncEnabled( true )
|
_syncEnabled( true )
|
||||||
@@ -48,11 +51,17 @@ FolderMan::FolderMan(QObject *parent) :
|
|||||||
this, SIGNAL(folderSyncStateChange(const QString &)));
|
this, SIGNAL(folderSyncStateChange(const QString &)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FolderMan *FolderMan::instance()
|
||||||
|
{
|
||||||
|
if(!_instance)
|
||||||
|
_instance = new FolderMan;
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
FolderMan::~FolderMan()
|
FolderMan::~FolderMan()
|
||||||
{
|
{
|
||||||
foreach (Folder *folder, _folderMap) {
|
qDeleteAll(_folderMap);
|
||||||
delete folder;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mirall::Folder::Map FolderMan::map()
|
Mirall::Folder::Map FolderMan::map()
|
||||||
@@ -64,15 +73,7 @@ Mirall::Folder::Map FolderMan::map()
|
|||||||
int FolderMan::setupFolders()
|
int FolderMan::setupFolders()
|
||||||
{
|
{
|
||||||
// setup a handler to look for configuration changes
|
// setup a handler to look for configuration changes
|
||||||
#ifdef CHECK_FOR_SETUP_CHANGES
|
return setupKnownFolders();
|
||||||
_configFolderWatcher = new FolderWatcher( _folderConfigPath );
|
|
||||||
_configFolderWatcher->setEventInterval(20000);
|
|
||||||
connect(_configFolderWatcher, SIGNAL(folderChanged(const QStringList &)),
|
|
||||||
this, SLOT( slotReparseConfiguration()) );
|
|
||||||
#endif
|
|
||||||
int cnt = setupKnownFolders();
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMan::slotReparseConfiguration()
|
void FolderMan::slotReparseConfiguration()
|
||||||
@@ -82,9 +83,6 @@ void FolderMan::slotReparseConfiguration()
|
|||||||
|
|
||||||
int FolderMan::unloadAllFolders()
|
int FolderMan::unloadAllFolders()
|
||||||
{
|
{
|
||||||
// first terminate sync jobs.
|
|
||||||
terminateCurrentSync();
|
|
||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
// clear the list of existing folders.
|
// clear the list of existing folders.
|
||||||
@@ -246,43 +244,28 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
|||||||
// QString connection = settings.value( QLatin1String("connection") ).toString();
|
// QString connection = settings.value( QLatin1String("connection") ).toString();
|
||||||
QString alias = unescapeAlias( escapedAlias );
|
QString alias = unescapeAlias( escapedAlias );
|
||||||
|
|
||||||
if (!backend.isEmpty()) {
|
if (backend.isEmpty() || backend != QLatin1String("owncloud")) {
|
||||||
|
qWarning() << "obsolete configuration of type" << backend;
|
||||||
if( backend == QLatin1String("owncloud") ) {
|
return 0;
|
||||||
MirallConfigFile cfgFile;
|
|
||||||
|
|
||||||
// assemble the owncloud url to pass to csync, incl. webdav
|
|
||||||
QString oCUrl = cfgFile.ownCloudUrl( QString::null, true );
|
|
||||||
|
|
||||||
// cut off the leading slash, oCUrl always has a trailing.
|
|
||||||
if( targetPath.startsWith(QLatin1Char('/')) ) {
|
|
||||||
targetPath.remove(0,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
folder = new ownCloudFolder( alias, path, oCUrl + targetPath, this );
|
|
||||||
folder->setConfigFile(file);
|
|
||||||
} else {
|
|
||||||
qWarning() << "unknown backend" << backend;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( folder ) {
|
// cut off the leading slash, oCUrl always has a trailing.
|
||||||
folder->setBackend( backend );
|
if( targetPath.startsWith(QLatin1Char('/')) ) {
|
||||||
// folder->setOnlyOnlineEnabled(settings.value("folder/onlyOnline", false).toBool());
|
targetPath.remove(0,1);
|
||||||
folder->setOnlyThisLANEnabled(settings.value(QLatin1String("folder/onlyThisLAN"), false).toBool());
|
|
||||||
|
|
||||||
_folderMap[alias] = folder;
|
|
||||||
|
|
||||||
qDebug() << "Adding folder to Folder Map " << folder;
|
|
||||||
/* Use a signal mapper to connect the signals to the alias */
|
|
||||||
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
|
|
||||||
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
|
|
||||||
connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted()));
|
|
||||||
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
|
|
||||||
|
|
||||||
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
folder = new Folder( alias, path, targetPath, this );
|
||||||
|
folder->setConfigFile(file);
|
||||||
|
qDebug() << "Adding folder to Folder Map " << folder;
|
||||||
|
_folderMap[alias] = folder;
|
||||||
|
|
||||||
|
/* Use a signal mapper to connect the signals to the alias */
|
||||||
|
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
|
||||||
|
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
|
||||||
|
connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted()));
|
||||||
|
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
|
||||||
|
|
||||||
|
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +296,7 @@ void FolderMan::terminateSyncProcess( const QString& alias )
|
|||||||
f->slotTerminateSync();
|
f->slotTerminateSync();
|
||||||
|
|
||||||
if(_currentSyncFolder == folderAlias )
|
if(_currentSyncFolder == folderAlias )
|
||||||
_currentSyncFolder = QString::null;
|
_currentSyncFolder.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,19 +313,21 @@ Folder *FolderMan::folder( const QString& alias )
|
|||||||
|
|
||||||
SyncResult FolderMan::syncResult( const QString& alias )
|
SyncResult FolderMan::syncResult( const QString& alias )
|
||||||
{
|
{
|
||||||
SyncResult res;
|
|
||||||
Folder *f = folder( alias );
|
Folder *f = folder( alias );
|
||||||
|
return syncResult(f);
|
||||||
|
}
|
||||||
|
|
||||||
if( f ) {
|
SyncResult FolderMan::syncResult( Folder *f )
|
||||||
res = f->syncResult();
|
{
|
||||||
}
|
return f ? f->syncResult() : SyncResult();
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMan::slotScheduleAllFolders()
|
void FolderMan::slotScheduleAllFolders()
|
||||||
{
|
{
|
||||||
foreach( Folder *f, _folderMap.values() ) {
|
foreach( Folder *f, _folderMap.values() ) {
|
||||||
slotScheduleSync( f->alias() );
|
if (f->syncEnabled()) {
|
||||||
|
slotScheduleSync( f->alias() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,17 +346,19 @@ void FolderMan::slotScheduleSync( const QString& alias )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( ! _scheduleQueue.contains(alias )) {
|
if( ! _scheduleQueue.contains(alias )) {
|
||||||
_scheduleQueue.append(alias);
|
_scheduleQueue.enqueue(alias);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << " II> Sync for folder " << alias << " already scheduled, do not enqueue!";
|
qDebug() << " II> Sync for folder " << alias << " already scheduled, do not enqueue!";
|
||||||
}
|
}
|
||||||
|
|
||||||
slotScheduleFolderSync();
|
slotScheduleFolderSync();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMan::setSyncEnabled( bool enabled )
|
void FolderMan::setSyncEnabled( bool enabled )
|
||||||
{
|
{
|
||||||
|
if (!_syncEnabled && enabled && !_scheduleQueue.isEmpty()) {
|
||||||
|
// We have things in our queue that were waiting the the connection to go back on.
|
||||||
|
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
|
||||||
|
}
|
||||||
_syncEnabled = enabled;
|
_syncEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,11 +381,14 @@ void FolderMan::slotScheduleFolderSync()
|
|||||||
|
|
||||||
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
|
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
|
||||||
if( ! _scheduleQueue.isEmpty() ) {
|
if( ! _scheduleQueue.isEmpty() ) {
|
||||||
const QString alias = _scheduleQueue.takeFirst();
|
const QString alias = _scheduleQueue.dequeue();
|
||||||
if( _folderMap.contains( alias ) ) {
|
if( _folderMap.contains( alias ) ) {
|
||||||
|
ownCloudInfo::instance()->getQuotaRequest("/");
|
||||||
Folder *f = _folderMap[alias];
|
Folder *f = _folderMap[alias];
|
||||||
_currentSyncFolder = alias;
|
_currentSyncFolder = alias;
|
||||||
f->startSync( QStringList() );
|
if (f->syncEnabled()) {
|
||||||
|
f->startSync( QStringList() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,28 +410,17 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
|
|||||||
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
|
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder, const QString& targetPath )
|
||||||
* Add a folder definition to the config
|
|
||||||
* Params:
|
|
||||||
* QString backend
|
|
||||||
* QString alias
|
|
||||||
* QString sourceFolder on local machine
|
|
||||||
* QString targetPath on remote
|
|
||||||
* bool onlyThisLAN, currently unused.
|
|
||||||
*/
|
|
||||||
void FolderMan::addFolderDefinition( const QString& backend, const QString& alias,
|
|
||||||
const QString& sourceFolder, const QString& targetPath,
|
|
||||||
bool onlyThisLAN )
|
|
||||||
{
|
{
|
||||||
QString escapedAlias = escapeAlias(alias);
|
QString escapedAlias = escapeAlias(alias);
|
||||||
// Create a settings file named after the alias
|
// Create a settings file named after the alias
|
||||||
QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat);
|
QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat);
|
||||||
|
settings.beginGroup(escapedAlias);
|
||||||
settings.setValue(QString::fromLatin1("%1/localPath").arg(escapedAlias), sourceFolder );
|
settings.setValue(QLatin1String("localPath"), sourceFolder );
|
||||||
settings.setValue(QString::fromLatin1("%1/targetPath").arg(escapedAlias), targetPath );
|
settings.setValue(QLatin1String("targetPath"), targetPath );
|
||||||
settings.setValue(QString::fromLatin1("%1/backend").arg(escapedAlias), backend );
|
// for compat reasons
|
||||||
settings.setValue(QString::fromLatin1("%1/connection").arg(escapedAlias), Theme::instance()->appName());
|
settings.setValue(QLatin1String("backend"), "owncloud" );
|
||||||
settings.setValue(QString::fromLatin1("%1/onlyThisLAN").arg(escapedAlias), onlyThisLAN );
|
settings.setValue(QLatin1String("connection"), Theme::instance()->appName());
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,11 +512,89 @@ bool FolderMan::startFromScratch( const QString& localFolder )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMan::setProxy()
|
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||||
{
|
{
|
||||||
foreach( Folder *f, _folderMap.values() ) {
|
SyncResult overallResult(SyncResult::Undefined);
|
||||||
f->setProxy();
|
|
||||||
|
foreach ( Folder *folder, folders ) {
|
||||||
|
SyncResult folderResult = folder->syncResult();
|
||||||
|
SyncResult::Status syncStatus = folderResult.status();
|
||||||
|
|
||||||
|
switch( syncStatus ) {
|
||||||
|
case SyncResult::Undefined:
|
||||||
|
if ( overallResult.status() != SyncResult::Error )
|
||||||
|
overallResult.setStatus(SyncResult::Error);
|
||||||
|
break;
|
||||||
|
case SyncResult::NotYetStarted:
|
||||||
|
overallResult.setStatus( SyncResult::NotYetStarted );
|
||||||
|
break;
|
||||||
|
case SyncResult::SyncPrepare:
|
||||||
|
overallResult.setStatus( SyncResult::SyncPrepare );
|
||||||
|
break;
|
||||||
|
case SyncResult::SyncRunning:
|
||||||
|
overallResult.setStatus( SyncResult::SyncRunning );
|
||||||
|
break;
|
||||||
|
case SyncResult::Unavailable:
|
||||||
|
overallResult.setStatus( SyncResult::Unavailable );
|
||||||
|
break;
|
||||||
|
case SyncResult::Success:
|
||||||
|
if( overallResult.status() == SyncResult::Undefined )
|
||||||
|
overallResult.setStatus( SyncResult::Success );
|
||||||
|
break;
|
||||||
|
case SyncResult::Error:
|
||||||
|
overallResult.setStatus( SyncResult::Error );
|
||||||
|
break;
|
||||||
|
case SyncResult::SetupError:
|
||||||
|
if ( overallResult.status() != SyncResult::Error )
|
||||||
|
overallResult.setStatus( SyncResult::SetupError );
|
||||||
|
break;
|
||||||
|
case SyncResult::Problem:
|
||||||
|
if ( overallResult.status() != SyncResult::Problem )
|
||||||
|
overallResult.setStatus( SyncResult::Problem );
|
||||||
|
break;
|
||||||
|
// no default case on purpose, check compiler warnings
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return overallResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FolderMan::statusToString( SyncResult syncStatus, bool enabled ) const
|
||||||
|
{
|
||||||
|
QString folderMessage;
|
||||||
|
switch( syncStatus.status() ) {
|
||||||
|
case SyncResult::Undefined:
|
||||||
|
folderMessage = tr( "Undefined State." );
|
||||||
|
break;
|
||||||
|
case SyncResult::NotYetStarted:
|
||||||
|
folderMessage = tr( "Waits to start syncing." );
|
||||||
|
break;
|
||||||
|
case SyncResult::SyncPrepare:
|
||||||
|
folderMessage = tr( "Preparing for sync." );
|
||||||
|
break;
|
||||||
|
case SyncResult::SyncRunning:
|
||||||
|
folderMessage = tr( "Sync is running." );
|
||||||
|
break;
|
||||||
|
case SyncResult::Unavailable:
|
||||||
|
folderMessage = tr( "Server is currently not available." );
|
||||||
|
break;
|
||||||
|
case SyncResult::Success:
|
||||||
|
folderMessage = tr( "Last Sync was successful." );
|
||||||
|
break;
|
||||||
|
case SyncResult::Error:
|
||||||
|
break;
|
||||||
|
case SyncResult::Problem:
|
||||||
|
folderMessage = tr( "Last Sync was successful, but with warnings on individual files.");
|
||||||
|
break;
|
||||||
|
case SyncResult::SetupError:
|
||||||
|
folderMessage = tr( "Setup Error." );
|
||||||
|
break;
|
||||||
|
// no default case on purpose, check compiler warnings
|
||||||
|
}
|
||||||
|
if( !enabled ) {
|
||||||
|
// sync is disabled.
|
||||||
|
folderMessage = tr( "%1 (Sync is paused)" ).arg(folderMessage);
|
||||||
|
}
|
||||||
|
return folderMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
#include "mirall/folder.h"
|
#include "mirall/folder.h"
|
||||||
#include "mirall/folderwatcher.h"
|
#include "mirall/folderwatcher.h"
|
||||||
@@ -25,15 +26,15 @@
|
|||||||
|
|
||||||
class QSignalMapper;
|
class QSignalMapper;
|
||||||
|
|
||||||
namespace Mirall {
|
|
||||||
|
|
||||||
class SyncResult;
|
class SyncResult;
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
class FolderMan : public QObject
|
class FolderMan : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit FolderMan(QObject *parent = 0);
|
static FolderMan* instance();
|
||||||
~FolderMan();
|
~FolderMan();
|
||||||
|
|
||||||
int setupFolders();
|
int setupFolders();
|
||||||
@@ -43,55 +44,43 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Add a folder definition to the config
|
* Add a folder definition to the config
|
||||||
* Params:
|
* Params:
|
||||||
* QString backend
|
|
||||||
* QString alias
|
* QString alias
|
||||||
* QString sourceFolder on local machine
|
* QString sourceFolder on local machine
|
||||||
* QString targetPath on remote
|
* QString targetPath on remote
|
||||||
* bool onlyThisLAN, currently unused.
|
|
||||||
*/
|
*/
|
||||||
void addFolderDefinition( const QString&, const QString&, const QString&, const QString&, bool );
|
void addFolderDefinition(const QString&, const QString&, const QString& );
|
||||||
|
|
||||||
/**
|
/** Returns the folder by alias or NULL if no folder with the alias exists. */
|
||||||
* return the folder by alias or NULL if no folder with the alias exists.
|
|
||||||
*/
|
|
||||||
Folder *folder( const QString& );
|
Folder *folder( const QString& );
|
||||||
|
|
||||||
/**
|
/** Returns the last sync result by alias */
|
||||||
* return the last sync result by alias
|
|
||||||
*/
|
|
||||||
SyncResult syncResult( const QString& );
|
SyncResult syncResult( const QString& );
|
||||||
|
|
||||||
/**
|
/** Returns the last sync result by Folder */
|
||||||
* creates a folder for a specific configuration, identified by alias.
|
SyncResult syncResult( Folder* );
|
||||||
*/
|
|
||||||
|
/** Creates a folder for a specific configuration, identified by alias. */
|
||||||
Folder* setupFolderFromConfigFile(const QString & );
|
Folder* setupFolderFromConfigFile(const QString & );
|
||||||
|
|
||||||
/**
|
/** Wipes all folder defintions. No way back! */
|
||||||
* wipes all folder defintions. No way back!
|
|
||||||
*/
|
|
||||||
void removeAllFolderDefinitions();
|
void removeAllFolderDefinitions();
|
||||||
|
|
||||||
/**
|
/** Removes csync journals from all folders. */
|
||||||
* Removes csync journals from all folders.
|
|
||||||
*/
|
|
||||||
void wipeAllJournals();
|
void wipeAllJournals();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that a given directory does not contain a .csync_journal.
|
* Ensures that a given directory does not contain a .csync_journal.
|
||||||
*
|
*
|
||||||
* @returns false if the journal could not be removed, false otherwise.
|
* @returns false if the journal could not be removed, true otherwise.
|
||||||
*/
|
*/
|
||||||
static bool ensureJournalGone(const QString &path);
|
static bool ensureJournalGone(const QString &path);
|
||||||
|
|
||||||
/**
|
/** Creates a new and empty local directory. */
|
||||||
* Creates a new and empty local directory.
|
|
||||||
*/
|
|
||||||
bool startFromScratch( const QString& );
|
bool startFromScratch( const QString& );
|
||||||
|
|
||||||
/**
|
QString statusToString( SyncResult, bool enabled ) const;
|
||||||
* called whenever proxy configuration changes
|
|
||||||
*/
|
static SyncResult accountStatus( const QList<Folder*> &folders );
|
||||||
void setProxy();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
@@ -141,14 +130,17 @@ private:
|
|||||||
|
|
||||||
void removeFolder( const QString& );
|
void removeFolder( const QString& );
|
||||||
|
|
||||||
FolderWatcher *_configFolderWatcher;
|
|
||||||
Folder::Map _folderMap;
|
Folder::Map _folderMap;
|
||||||
QString _folderConfigPath;
|
QString _folderConfigPath;
|
||||||
QSignalMapper *_folderChangeSignalMapper;
|
QSignalMapper *_folderChangeSignalMapper;
|
||||||
QString _currentSyncFolder;
|
QString _currentSyncFolder;
|
||||||
QStringList _scheduleQueue;
|
|
||||||
bool _syncEnabled;
|
bool _syncEnabled;
|
||||||
|
QQueue<QString> _scheduleQueue;
|
||||||
|
|
||||||
|
explicit FolderMan(QObject *parent = 0);
|
||||||
|
static FolderMan *_instance;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Mirall
|
||||||
#endif // FOLDERMAN_H
|
#endif // FOLDERMAN_H
|
||||||
|
|||||||
304
src/mirall/folderstatusmodel.cpp
Normal file
304
src/mirall/folderstatusmodel.cpp
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
*
|
||||||
|
* 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 "mirall/folderstatusmodel.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
FolderStatusModel::FolderStatusModel()
|
||||||
|
:QStandardItemModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex& ) const
|
||||||
|
{
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (role == Qt::EditRole)
|
||||||
|
return QVariant();
|
||||||
|
else
|
||||||
|
return QStandardItemModel::data(index,role);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================================================================================
|
||||||
|
|
||||||
|
FolderStatusDelegate::FolderStatusDelegate()
|
||||||
|
:QStyledItemDelegate()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderStatusDelegate::~FolderStatusDelegate()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated destructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
//alocate each item size in listview.
|
||||||
|
QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem & option ,
|
||||||
|
const QModelIndex & index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(option)
|
||||||
|
QFont aliasFont = option.font;
|
||||||
|
QFont font = option.font;
|
||||||
|
aliasFont.setPointSize( font.pointSize() +2 );
|
||||||
|
|
||||||
|
QFontMetrics fm(font);
|
||||||
|
QFontMetrics aliasFm(aliasFont);
|
||||||
|
|
||||||
|
int aliasMargin = aliasFm.height()/2;
|
||||||
|
int margin = fm.height()/4;
|
||||||
|
|
||||||
|
// calc height
|
||||||
|
|
||||||
|
int h = aliasMargin; // margin to top
|
||||||
|
h += aliasFm.height(); // alias
|
||||||
|
h += margin; // between alias and local path
|
||||||
|
h += fm.height(); // local path
|
||||||
|
h += margin; // between local and remote path
|
||||||
|
h += fm.height(); // remote path
|
||||||
|
h += aliasMargin; // bottom margin
|
||||||
|
|
||||||
|
// add some space to show an error condition.
|
||||||
|
if( ! qvariant_cast<QString>(index.data(FolderErrorMsg)).isEmpty() ) {
|
||||||
|
h += aliasMargin*2+fm.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( qvariant_cast<bool>(index.data(AddProgressSpace)) ) {
|
||||||
|
int margin = fm.height()/4;
|
||||||
|
h += (5 * margin); // All the margins
|
||||||
|
h += 2* fm.boundingRect(tr("File")).height();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSize( 0, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QStyledItemDelegate::paint(painter,option,index);
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QFont aliasFont = option.font;
|
||||||
|
QFont subFont = option.font;
|
||||||
|
QFont errorFont = subFont;
|
||||||
|
QFont progressFont = subFont;
|
||||||
|
|
||||||
|
progressFont.setPointSize( subFont.pointSize()-1);
|
||||||
|
//font.setPixelSize(font.weight()+);
|
||||||
|
aliasFont.setBold(true);
|
||||||
|
aliasFont.setPointSize( subFont.pointSize()+2 );
|
||||||
|
|
||||||
|
QFontMetrics subFm( subFont );
|
||||||
|
QFontMetrics aliasFm( aliasFont );
|
||||||
|
QFontMetrics progressFm( progressFont );
|
||||||
|
|
||||||
|
int aliasMargin = aliasFm.height()/2;
|
||||||
|
int margin = subFm.height()/4;
|
||||||
|
|
||||||
|
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole));
|
||||||
|
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
|
||||||
|
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
|
||||||
|
QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole));
|
||||||
|
QString errorText = qvariant_cast<QString>(index.data(FolderErrorMsg));
|
||||||
|
|
||||||
|
int overallPercent = qvariant_cast<int>(index.data(SyncProgressOverallPercent));
|
||||||
|
QString overallString = qvariant_cast<QString>(index.data(SyncProgressOverallString));
|
||||||
|
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
||||||
|
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
||||||
|
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
||||||
|
// QString statusText = qvariant_cast<QString>(index.data(FolderStatus));
|
||||||
|
bool syncEnabled = index.data(FolderSyncEnabled).toBool();
|
||||||
|
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
|
||||||
|
|
||||||
|
QRect iconRect = option.rect;
|
||||||
|
QRect aliasRect = option.rect;
|
||||||
|
|
||||||
|
iconRect.setLeft( aliasMargin );
|
||||||
|
iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2);
|
||||||
|
|
||||||
|
// alias box
|
||||||
|
aliasRect.setTop(aliasRect.top() + aliasMargin );
|
||||||
|
aliasRect.setBottom(aliasRect.top() + aliasFm.height());
|
||||||
|
aliasRect.setRight(aliasRect.right() - aliasMargin );
|
||||||
|
|
||||||
|
// remote directory box
|
||||||
|
QRect remotePathRect = aliasRect;
|
||||||
|
remotePathRect.setTop(aliasRect.bottom() + margin );
|
||||||
|
remotePathRect.setBottom(remotePathRect.top() + subFm.height());
|
||||||
|
|
||||||
|
// local directory box
|
||||||
|
QRect localPathRect = remotePathRect;
|
||||||
|
localPathRect.setTop( remotePathRect.bottom() + margin );
|
||||||
|
localPathRect.setBottom( localPathRect.top() + subFm.height());
|
||||||
|
|
||||||
|
iconRect.setBottom(localPathRect.bottom());
|
||||||
|
iconRect.setWidth(iconRect.height());
|
||||||
|
|
||||||
|
int nextToIcon = iconRect.right()+aliasMargin;
|
||||||
|
aliasRect.setLeft(nextToIcon);
|
||||||
|
localPathRect.setLeft(nextToIcon);
|
||||||
|
remotePathRect.setLeft(nextToIcon);
|
||||||
|
|
||||||
|
int iconSize = iconRect.width();
|
||||||
|
|
||||||
|
QPixmap pm = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled );
|
||||||
|
painter->drawPixmap(QPoint(iconRect.left(), iconRect.top()), pm);
|
||||||
|
|
||||||
|
// only show the warning icon if the sync is running. Otherwise its
|
||||||
|
// encoded in the status icon.
|
||||||
|
if( warningCount > 0 && syncOngoing) {
|
||||||
|
QRect warnRect;
|
||||||
|
warnRect.setLeft(iconRect.left());
|
||||||
|
warnRect.setTop(iconRect.bottom()-17);
|
||||||
|
warnRect.setWidth(16);
|
||||||
|
warnRect.setHeight(16);
|
||||||
|
|
||||||
|
QIcon warnIcon(":/mirall/resources/warning-16");
|
||||||
|
QPixmap pm = warnIcon.pixmap(16,16, syncEnabled ? QIcon::Normal : QIcon::Disabled );
|
||||||
|
painter->drawPixmap(QPoint(warnRect.left(), warnRect.top()),pm );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((option.state & QStyle::State_Selected)
|
||||||
|
&& (option.state & QStyle::State_Active)
|
||||||
|
// Hack: Windows Vista's light blue is not contrasting enough for white
|
||||||
|
&& !qApp->style()->inherits("QWindowsVistaStyle")) {
|
||||||
|
painter->setPen(option.palette.color(QPalette::HighlightedText));
|
||||||
|
} else {
|
||||||
|
painter->setPen(option.palette.color(QPalette::Text));
|
||||||
|
}
|
||||||
|
QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width());
|
||||||
|
painter->setFont(aliasFont);
|
||||||
|
painter->drawText(aliasRect, elidedAlias);
|
||||||
|
|
||||||
|
painter->setFont(subFont);
|
||||||
|
QString elidedRemotePathText;
|
||||||
|
|
||||||
|
if (remotePath.isEmpty() || remotePath == QLatin1String("/")) {
|
||||||
|
elidedRemotePathText = subFm.elidedText(tr("Syncing all files in your account with"),
|
||||||
|
Qt::ElideRight, remotePathRect.width());
|
||||||
|
} else {
|
||||||
|
elidedRemotePathText = subFm.elidedText(tr("Remote path: %1").arg(remotePath),
|
||||||
|
Qt::ElideMiddle, remotePathRect.width());
|
||||||
|
}
|
||||||
|
painter->drawText(remotePathRect, elidedRemotePathText);
|
||||||
|
|
||||||
|
QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width());
|
||||||
|
painter->drawText(localPathRect, elidedPathText);
|
||||||
|
|
||||||
|
// paint an error overlay if there is an error string
|
||||||
|
|
||||||
|
int h = iconRect.bottom();
|
||||||
|
if( !errorText.isEmpty() ) {
|
||||||
|
h += aliasMargin;
|
||||||
|
QRect errorRect = localPathRect;
|
||||||
|
errorRect.setLeft( iconRect.left());
|
||||||
|
errorRect.setTop( h );
|
||||||
|
errorRect.setHeight(subFm.height()+aliasMargin);
|
||||||
|
errorRect.setRight( option.rect.right()-aliasMargin );
|
||||||
|
|
||||||
|
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
|
||||||
|
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
|
||||||
|
painter->drawRoundedRect( errorRect, 4, 4 );
|
||||||
|
|
||||||
|
painter->setPen( Qt::white );
|
||||||
|
painter->setFont(errorFont);
|
||||||
|
QRect errorTextRect = errorRect;
|
||||||
|
errorTextRect.setLeft( errorTextRect.left()+aliasMargin +16);
|
||||||
|
errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 );
|
||||||
|
|
||||||
|
int linebreak = errorText.indexOf(QLatin1String("<br"));
|
||||||
|
QString eText = errorText;
|
||||||
|
if(linebreak) {
|
||||||
|
eText = errorText.left(linebreak);
|
||||||
|
}
|
||||||
|
painter->drawText(errorTextRect, eText);
|
||||||
|
|
||||||
|
h = errorRect.bottom();
|
||||||
|
}
|
||||||
|
h += aliasMargin;
|
||||||
|
|
||||||
|
// Sync File Progress Bar: Show it if syncFile is not empty.
|
||||||
|
if( !overallString.isEmpty()) {
|
||||||
|
int fileNameTextHeight = subFm.boundingRect(tr("File")).height();
|
||||||
|
int barHeight = fileNameTextHeight;
|
||||||
|
int overallWidth = option.rect.width()-2*aliasMargin;
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
// Sizes-Text
|
||||||
|
QRect octetRect = subFm.boundingRect( overallString );
|
||||||
|
int progressTextWidth = octetRect.width();
|
||||||
|
|
||||||
|
// Overall Progress Bar.
|
||||||
|
QRect pBRect;
|
||||||
|
pBRect.setTop( h );
|
||||||
|
pBRect.setLeft( iconRect.left());
|
||||||
|
pBRect.setHeight(barHeight);
|
||||||
|
pBRect.setWidth( overallWidth - progressTextWidth - margin );
|
||||||
|
|
||||||
|
QStyleOptionProgressBarV2 pBarOpt;
|
||||||
|
pBarOpt.state = option.state | QStyle::State_Horizontal;
|
||||||
|
pBarOpt.minimum = 0;
|
||||||
|
pBarOpt.maximum = 100;
|
||||||
|
pBarOpt.progress = overallPercent;
|
||||||
|
pBarOpt.orientation = Qt::Horizontal;
|
||||||
|
pBarOpt.palette = option.palette;
|
||||||
|
pBarOpt.rect = pBRect;
|
||||||
|
|
||||||
|
QApplication::style()->drawControl( QStyle::CE_ProgressBar, &pBarOpt, painter );
|
||||||
|
|
||||||
|
// Overall Progress Text
|
||||||
|
QRect overallProgressRect;
|
||||||
|
overallProgressRect.setTop( pBRect.top() );
|
||||||
|
overallProgressRect.setHeight( pBRect.height() );
|
||||||
|
overallProgressRect.setLeft( pBRect.right()+margin);
|
||||||
|
overallProgressRect.setWidth( progressTextWidth );
|
||||||
|
painter->setFont(progressFont);
|
||||||
|
|
||||||
|
QString elidedText = progressFm.elidedText(overallString, Qt::ElideLeft, overallProgressRect.width());
|
||||||
|
painter->drawText( overallProgressRect, Qt::AlignRight+Qt::AlignVCenter, elidedText);
|
||||||
|
|
||||||
|
// Individual File Progress
|
||||||
|
QRect fileRect;
|
||||||
|
fileRect.setTop( pBRect.bottom() + margin);
|
||||||
|
fileRect.setLeft( iconRect.left());
|
||||||
|
fileRect.setWidth(overallWidth);
|
||||||
|
fileRect.setHeight(fileNameTextHeight);
|
||||||
|
elidedText = progressFm.elidedText(itemString, Qt::ElideLeft, fileRect.width());
|
||||||
|
|
||||||
|
painter->drawText( fileRect, Qt::AlignLeft+Qt::AlignVCenter, elidedText);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FolderStatusDelegate::editorEvent ( QEvent * /*event*/, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/ )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
66
src/mirall/folderstatusmodel.h
Normal file
66
src/mirall/folderstatusmodel.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FOLDERSTATUSMODEL_H
|
||||||
|
#define FOLDERSTATUSMODEL_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
class FolderStatusModel : public QStandardItemModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FolderStatusModel();
|
||||||
|
virtual Qt::ItemFlags flags( const QModelIndex& ) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class FolderStatusDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
FolderStatusDelegate();
|
||||||
|
virtual ~FolderStatusDelegate();
|
||||||
|
|
||||||
|
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
||||||
|
FolderPathRole,
|
||||||
|
FolderSecondPathRole,
|
||||||
|
FolderRemotePath,
|
||||||
|
FolderStatus,
|
||||||
|
FolderErrorMsg,
|
||||||
|
FolderSyncEnabled,
|
||||||
|
FolderStatusIconRole,
|
||||||
|
|
||||||
|
SyncProgressOverallPercent,
|
||||||
|
SyncProgressOverallString,
|
||||||
|
SyncProgressItemString,
|
||||||
|
AddProgressSpace,
|
||||||
|
WarningCount,
|
||||||
|
SyncRunning
|
||||||
|
};
|
||||||
|
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||||
|
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||||
|
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index );
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _addProgressSpace;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
|
||||||
|
#endif // FOLDERSTATUSMODEL_H
|
||||||
@@ -69,7 +69,7 @@ QString FolderWatcher::root() const
|
|||||||
return _root;
|
return _root;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWatcher::setIgnoreListFile( const QString& file )
|
void FolderWatcher::addIgnoreListFile( const QString& file )
|
||||||
{
|
{
|
||||||
if( file.isEmpty() ) return;
|
if( file.isEmpty() ) return;
|
||||||
|
|
||||||
@@ -79,18 +79,12 @@ void FolderWatcher::setIgnoreListFile( const QString& file )
|
|||||||
|
|
||||||
while (!infile.atEnd()) {
|
while (!infile.atEnd()) {
|
||||||
QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed();
|
QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed();
|
||||||
if( !line.startsWith( QLatin1Char('#') )) {
|
if( !line.startsWith( QLatin1Char('#') ) && line.isEmpty() ) {
|
||||||
addIgnore(line);
|
_ignores.append(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWatcher::addIgnore(const QString &pattern)
|
|
||||||
{
|
|
||||||
if( pattern.isEmpty() ) return;
|
|
||||||
_ignores.append(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList FolderWatcher::ignores() const
|
QStringList FolderWatcher::ignores() const
|
||||||
{
|
{
|
||||||
return _ignores;
|
return _ignores;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class FolderWatcherPrivate;
|
|||||||
*/
|
*/
|
||||||
class FolderWatcher : public QObject
|
class FolderWatcher : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @param root Path of the root of the folder
|
* @param root Path of the root of the folder
|
||||||
@@ -58,16 +58,11 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a file name to load a file with ignore patterns.
|
* Set a file name to load a file with ignore patterns.
|
||||||
|
*
|
||||||
|
* Valid entries do not start with a hash sign (#)
|
||||||
|
* and may contain wildcards
|
||||||
*/
|
*/
|
||||||
void setIgnoreListFile( const QString& );
|
void addIgnoreListFile( const QString& );
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an ignore pattern that will not be
|
|
||||||
* notified
|
|
||||||
*
|
|
||||||
* You can use wildcards
|
|
||||||
*/
|
|
||||||
void addIgnore(const QString &pattern);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, folderChanged() events are sent
|
* If true, folderChanged() events are sent
|
||||||
@@ -109,10 +104,10 @@ public slots:
|
|||||||
void setEventsEnabledDelayed( int );
|
void setEventsEnabledDelayed( int );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/** Emitted when one of the paths is changed */
|
||||||
* Emitted when one of the paths is changed
|
|
||||||
*/
|
|
||||||
void folderChanged(const QStringList &pathList);
|
void folderChanged(const QStringList &pathList);
|
||||||
|
/** Emitted if an error occurs */
|
||||||
|
void error(const QString& error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setProcessTimer();
|
void setProcessTimer();
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p)
|
|||||||
|
|
||||||
{
|
{
|
||||||
_inotify = new INotify(this, standard_event_mask);
|
_inotify = new INotify(this, standard_event_mask);
|
||||||
slotAddFolderRecursive(_parent->root());
|
|
||||||
QObject::connect(_inotify, SIGNAL(notifyEvent(int, int, const QString &)),
|
QObject::connect(_inotify, SIGNAL(notifyEvent(int, int, const QString &)),
|
||||||
this, SLOT(slotINotifyEvent(int, int, const QString &)));
|
this, SLOT(slotINotifyEvent(int, int, const QString &)));
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(this, "slotAddFolderRecursive", Q_ARG(QString, _parent->root()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
||||||
@@ -49,7 +49,12 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
|||||||
int subdirs = 0;
|
int subdirs = 0;
|
||||||
qDebug() << "(+) Watcher:" << path;
|
qDebug() << "(+) Watcher:" << path;
|
||||||
|
|
||||||
_inotify->addPath(path);
|
if (!_inotify->addPath(path)) {
|
||||||
|
FolderWatcher *fw = qobject_cast<FolderWatcher*>(parent());
|
||||||
|
emit fw->error(tr("Could not monitor directories due to system limitations.\n"
|
||||||
|
"The application will not work reliably. Please check the\n"
|
||||||
|
"documentation for possible fixes."));
|
||||||
|
}
|
||||||
QStringList watchedFolders(_inotify->directories());
|
QStringList watchedFolders(_inotify->directories());
|
||||||
// qDebug() << "currently watching " << watchedFolders;
|
// qDebug() << "currently watching " << watchedFolders;
|
||||||
QStringListIterator subfoldersIt(FileUtils::subFoldersList(path, FileUtils::SubFolderRecursive));
|
QStringListIterator subfoldersIt(FileUtils::subFoldersList(path, FileUtils::SubFolderRecursive));
|
||||||
@@ -78,7 +83,7 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
|||||||
qDebug() << " `-> and" << subdirs << "subdirectories";
|
qDebug() << " `-> and" << subdirs << "subdirectories";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWatcherPrivate::slotINotifyEvent(int mask, int cookie, const QString &path)
|
void FolderWatcherPrivate::slotINotifyEvent(int mask, int /*cookie*/, const QString &path)
|
||||||
{
|
{
|
||||||
int lastMask = _lastMask;
|
int lastMask = _lastMask;
|
||||||
QString lastPath = _lastPath;
|
QString lastPath = _lastPath;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ class FolderWatcherPrivate : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FolderWatcherPrivate(FolderWatcher *p);
|
FolderWatcherPrivate(FolderWatcher *p);
|
||||||
|
signals:
|
||||||
|
void error(const QString& error);
|
||||||
private slots:
|
private slots:
|
||||||
void slotAddFolderRecursive(const QString &path);
|
void slotAddFolderRecursive(const QString &path);
|
||||||
void slotINotifyEvent(int mask, int cookie, const QString &path);
|
void slotINotifyEvent(int mask, int cookie, const QString &path);
|
||||||
|
|||||||
@@ -19,12 +19,15 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QDir>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QFileIconProvider>
|
||||||
|
#include <QInputDialog>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
#include <QWizardPage>
|
#include <QWizardPage>
|
||||||
#include <QDir>
|
#include <QTreeWidget>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -32,7 +35,7 @@ namespace Mirall
|
|||||||
{
|
{
|
||||||
|
|
||||||
FolderWizardSourcePage::FolderWizardSourcePage()
|
FolderWizardSourcePage::FolderWizardSourcePage()
|
||||||
:_folderMap(0)
|
: QWizardPage()
|
||||||
{
|
{
|
||||||
_ui.setupUi(this);
|
_ui.setupUi(this);
|
||||||
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
|
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
|
||||||
@@ -42,10 +45,6 @@ FolderWizardSourcePage::FolderWizardSourcePage()
|
|||||||
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
|
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
|
||||||
|
|
||||||
_ui.warnLabel->hide();
|
_ui.warnLabel->hide();
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
_ui.localFolderLineEdit->setPlaceholderText(QApplication::translate("FolderWizardSourcePage", "/home/local1", 0, QApplication::UnicodeUTF8));
|
|
||||||
_ui.aliasLineEdit->setPlaceholderText(QApplication::translate("FolderWizardSourcePage", "Music", 0, QApplication::UnicodeUTF8));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderWizardSourcePage::~FolderWizardSourcePage()
|
FolderWizardSourcePage::~FolderWizardSourcePage()
|
||||||
@@ -72,15 +71,20 @@ bool FolderWizardSourcePage::isComplete() const
|
|||||||
|
|
||||||
bool isOk = selFile.isDir();
|
bool isOk = selFile.isDir();
|
||||||
if( !isOk ) {
|
if( !isOk ) {
|
||||||
warnString = tr("No local directory selected!");
|
warnString = tr("No local folder selected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isOk && !selFile.isWritable()) {
|
||||||
|
isOk = false;
|
||||||
|
warnString += tr("You have no permission to write to the selected folder!");
|
||||||
|
}
|
||||||
|
|
||||||
// check if the local directory isn't used yet in another ownCloud sync
|
// check if the local directory isn't used yet in another ownCloud sync
|
||||||
Folder::Map *map = _folderMap;
|
Folder::Map map = _folderMap;
|
||||||
if( ! map ) return false;
|
|
||||||
|
|
||||||
if( isOk ) {
|
if( isOk ) {
|
||||||
Folder::Map::const_iterator i = map->constBegin();
|
Folder::Map::const_iterator i = map.constBegin();
|
||||||
while( isOk && i != map->constEnd() ) {
|
while( isOk && i != map.constEnd() ) {
|
||||||
Folder *f = static_cast<Folder*>(i.value());
|
Folder *f = static_cast<Folder*>(i.value());
|
||||||
QString folderDir = QDir( f->path() ).canonicalPath();
|
QString folderDir = QDir( f->path() ).canonicalPath();
|
||||||
if( folderDir.isEmpty() )
|
if( folderDir.isEmpty() )
|
||||||
@@ -119,10 +123,10 @@ bool FolderWizardSourcePage::isComplete() const
|
|||||||
isOk = false;
|
isOk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Folder::Map::const_iterator i = map->constBegin();
|
Folder::Map::const_iterator i = map.constBegin();
|
||||||
bool goon = true;
|
bool goon = true;
|
||||||
while( goon && i != map->constEnd() ) {
|
while( goon && i != map.constEnd() ) {
|
||||||
Folder *f = static_cast<Folder*>(i.value());
|
Folder *f = i.value();
|
||||||
qDebug() << "Checking local alias: " << f->alias();
|
qDebug() << "Checking local alias: " << f->alias();
|
||||||
if( f ) {
|
if( f ) {
|
||||||
if( f->alias() == alias ) {
|
if( f->alias() == alias ) {
|
||||||
@@ -162,64 +166,38 @@ void FolderWizardSourcePage::on_localFolderLineEdit_textChanged()
|
|||||||
|
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
FolderWizardTargetPage::FolderWizardTargetPage()
|
FolderWizardTargetPage::FolderWizardTargetPage()
|
||||||
: _dirChecked( false ),
|
: _warnWasVisible(false)
|
||||||
_warnWasVisible(false)
|
|
||||||
{
|
{
|
||||||
_ui.setupUi(this);
|
_ui.setupUi(this);
|
||||||
_ui.warnFrame->hide();
|
_ui.warnFrame->hide();
|
||||||
|
|
||||||
registerField(QLatin1String("OCFolderLineEdit"), _ui.OCFolderLineEdit);
|
connect(_ui.addFolderButton, SIGNAL(clicked()), SLOT(slotAddRemoteFolder()));
|
||||||
|
connect(_ui.refreshButton, SIGNAL(clicked()), SLOT(slotRefreshFolders()));
|
||||||
connect( _ui.OCFolderLineEdit, SIGNAL(textChanged(QString)),
|
connect(_ui.folderTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
|
||||||
SLOT(slotFolderTextChanged(QString)));
|
connect(_ui.folderTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
|
||||||
|
|
||||||
_timer = new QTimer(this);
|
|
||||||
_timer->setSingleShot( true );
|
|
||||||
connect( _timer, SIGNAL(timeout()), SLOT(slotTimerFires()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWizardTargetPage::slotFolderTextChanged( const QString& t)
|
void FolderWizardTargetPage::slotAddRemoteFolder()
|
||||||
{
|
{
|
||||||
_dirChecked = false;
|
QTreeWidgetItem *current = _ui.folderTreeWidget->currentItem();
|
||||||
emit completeChanged();
|
|
||||||
|
|
||||||
if( t.isEmpty() ) {
|
QString parent('/');
|
||||||
_timer->stop();
|
if (current) {
|
||||||
return;
|
parent = current->data(0, Qt::UserRole).toString();
|
||||||
}
|
|
||||||
|
|
||||||
if( _timer->isActive() ) _timer->stop();
|
|
||||||
_timer->start(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderWizardTargetPage::slotTimerFires()
|
|
||||||
{
|
|
||||||
const QString folder = _ui.OCFolderLineEdit->text();
|
|
||||||
qDebug() << "Querying folder " << folder;
|
|
||||||
ownCloudInfo::instance()->getWebDAVPath( folder );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderWizardTargetPage::slotDirCheckReply(const QString &url, QNetworkReply *reply)
|
|
||||||
{
|
|
||||||
qDebug() << "Got reply from owncloud dir check: " << url << " :" << reply->error();
|
|
||||||
_dirChecked = (reply->error() == QNetworkReply::NoError);
|
|
||||||
if( _dirChecked ) {
|
|
||||||
showWarn();
|
|
||||||
} else {
|
|
||||||
showWarn( tr("The folder is not available on your %1.<br/>Click to create it." )
|
|
||||||
.arg( Theme::instance()->appNameGUI() ), true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit completeChanged();
|
QInputDialog *dlg = new QInputDialog(this);
|
||||||
|
|
||||||
|
dlg->setWindowTitle(tr("Add Remote Folder"));
|
||||||
|
dlg->setLabelText(tr("Enter the name of the new folder:"));
|
||||||
|
dlg->setTextValue(parent);
|
||||||
|
dlg->open(this, SLOT(slotCreateRemoteFolder(QString)));
|
||||||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWizardTargetPage::slotCreateRemoteFolder()
|
void FolderWizardTargetPage::slotCreateRemoteFolder(QString folder)
|
||||||
{
|
{
|
||||||
const QString folder = _ui.OCFolderLineEdit->text();
|
|
||||||
if( folder.isEmpty() ) return;
|
if( folder.isEmpty() ) return;
|
||||||
|
|
||||||
_ui.OCFolderLineEdit->setEnabled( false );
|
|
||||||
qDebug() << "creating folder on ownCloud: " << folder;
|
|
||||||
ownCloudInfo::instance()->mkdirRequest( folder );
|
ownCloudInfo::instance()->mkdirRequest( folder );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,32 +205,105 @@ void FolderWizardTargetPage::slotCreateRemoteFolderFinished( QNetworkReply::Netw
|
|||||||
{
|
{
|
||||||
qDebug() << "** webdav mkdir request finished " << error;
|
qDebug() << "** webdav mkdir request finished " << error;
|
||||||
|
|
||||||
_ui.OCFolderLineEdit->setEnabled( true );
|
|
||||||
// the webDAV server seems to return a 202 even if mkdir was successful.
|
// the webDAV server seems to return a 202 even if mkdir was successful.
|
||||||
if( error == QNetworkReply::NoError ||
|
if( error == QNetworkReply::NoError ||
|
||||||
error == QNetworkReply::ContentOperationNotPermittedError) {
|
error == QNetworkReply::ContentOperationNotPermittedError) {
|
||||||
showWarn( tr("Folder was successfully created on %1.").arg( Theme::instance()->appNameGUI() ), false );
|
showWarn( tr("Folder was successfully created on %1.").arg( Theme::instance()->appNameGUI() ) );
|
||||||
slotTimerFires();
|
slotRefreshFolders();
|
||||||
} else {
|
} else {
|
||||||
showWarn( tr("Failed to create the folder on %1.<br/>Please check manually.").arg( Theme::instance()->appNameGUI() ), false );
|
showWarn( tr("Failed to create the folder on %1.<br/>Please check manually.").arg( Theme::instance()->appNameGUI() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& text)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < parent->childCount(); ++i) {
|
||||||
|
QTreeWidgetItem *child = parent->child(i);
|
||||||
|
if (child->text(0) == text) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path)
|
||||||
|
{
|
||||||
|
QFileIconProvider prov;
|
||||||
|
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||||
|
if (pathTrail.size() == 0) {
|
||||||
|
if (path.endsWith('/')) {
|
||||||
|
path.chop(1);
|
||||||
|
}
|
||||||
|
parent->setToolTip(0, path);
|
||||||
|
parent->setData(0, Qt::UserRole, path);
|
||||||
|
} else {
|
||||||
|
QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
|
||||||
|
if (!item) {
|
||||||
|
item = new QTreeWidgetItem(parent);
|
||||||
|
item->setIcon(0, folderIcon);
|
||||||
|
item->setText(0, pathTrail.first());
|
||||||
|
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pathTrail.removeFirst();
|
||||||
|
recursiveInsert(item, pathTrail, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderWizardTargetPage::slotUpdateDirectories(QStringList list)
|
||||||
|
{
|
||||||
|
QFileIconProvider prov;
|
||||||
|
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||||
|
|
||||||
|
QString webdavFolder = QUrl(ownCloudInfo::instance()->webdavUrl()).path();
|
||||||
|
connect(_ui.folderTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||||
|
|
||||||
|
QTreeWidgetItem *root = _ui.folderTreeWidget->topLevelItem(0);
|
||||||
|
if (!root) {
|
||||||
|
root = new QTreeWidgetItem(_ui.folderTreeWidget);
|
||||||
|
root->setText(0, tr("Root (\"/\")", "root folder"));
|
||||||
|
root->setIcon(0, folderIcon);
|
||||||
|
root->setToolTip(0, tr("Choose this to sync the entire account"));
|
||||||
|
root->setData(0, Qt::UserRole, "/");
|
||||||
|
}
|
||||||
|
foreach (QString path, list) {
|
||||||
|
path.remove(webdavFolder);
|
||||||
|
QStringList paths = path.split('/');
|
||||||
|
if (paths.last().isEmpty()) paths.removeLast();
|
||||||
|
recursiveInsert(root, paths, path);
|
||||||
|
}
|
||||||
|
root->setExpanded(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderWizardTargetPage::slotRefreshFolders()
|
||||||
|
{
|
||||||
|
ownCloudInfo::instance()->getDirectoryListing("/");
|
||||||
|
_ui.folderTreeWidget->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderWizardTargetPage::slotItemExpanded(QTreeWidgetItem *item)
|
||||||
|
{
|
||||||
|
ownCloudInfo::instance()->getDirectoryListing(item->text(0));
|
||||||
|
}
|
||||||
|
|
||||||
FolderWizardTargetPage::~FolderWizardTargetPage()
|
FolderWizardTargetPage::~FolderWizardTargetPage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderWizardTargetPage::isComplete() const
|
bool FolderWizardTargetPage::isComplete() const
|
||||||
{
|
{
|
||||||
QString dir = _ui.OCFolderLineEdit->text();
|
if (!_ui.folderTreeWidget->currentItem())
|
||||||
if( dir.isEmpty() || dir == QLatin1String("/") ) {
|
return false;
|
||||||
showWarn( tr("If you sync the root folder, you can <b>not</b> configure another sync directory."), false);
|
|
||||||
|
QString dir = _ui.folderTreeWidget->currentItem()->data(0, Qt::UserRole).toString();
|
||||||
|
wizard()->setProperty("targetPath", dir);
|
||||||
|
|
||||||
|
if( dir == QLatin1String("/") ) {
|
||||||
|
showWarn( tr("If you sync the root folder, you can <b>not</b> configure another sync directory."));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if( _dirChecked ) {
|
showWarn();
|
||||||
showWarn();
|
return true;
|
||||||
}
|
|
||||||
return _dirChecked;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,53 +319,19 @@ void FolderWizardTargetPage::initializePage()
|
|||||||
/* check the owncloud configuration file and query the ownCloud */
|
/* check the owncloud configuration file and query the ownCloud */
|
||||||
ownCloudInfo *ocInfo = ownCloudInfo::instance();
|
ownCloudInfo *ocInfo = ownCloudInfo::instance();
|
||||||
if( ocInfo->isConfigured() ) {
|
if( ocInfo->isConfigured() ) {
|
||||||
connect( ocInfo, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
|
||||||
SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
|
|
||||||
connect( ocInfo, SIGNAL(noOwncloudFound(QNetworkReply*)),
|
|
||||||
SLOT(slotNoOwnCloudFound(QNetworkReply*)));
|
|
||||||
connect( ocInfo, SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
connect( ocInfo, SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
||||||
SLOT(slotDirCheckReply(QString,QNetworkReply*)));
|
SLOT(slotDirCheckReply(QString,QNetworkReply*)));
|
||||||
connect( ocInfo, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
|
connect( ocInfo, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
|
||||||
SLOT(slotCreateRemoteFolderFinished( QNetworkReply::NetworkError )));
|
SLOT(slotCreateRemoteFolderFinished( QNetworkReply::NetworkError )));
|
||||||
|
connect( ocInfo, SIGNAL(directoryListingUpdated(QStringList)),
|
||||||
|
SLOT(slotUpdateDirectories(QStringList)));
|
||||||
|
|
||||||
connect(_ui._buttCreateFolder, SIGNAL(clicked()), SLOT(slotCreateRemoteFolder()));
|
slotRefreshFolders();
|
||||||
ocInfo->checkInstallation();
|
|
||||||
|
|
||||||
_ui.OCFolderLineEdit->setEnabled( false );
|
|
||||||
|
|
||||||
QString dir = _ui.OCFolderLineEdit->text();
|
|
||||||
if( !dir.isEmpty() ) {
|
|
||||||
slotFolderTextChanged( dir );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void FolderWizardTargetPage::slotOwnCloudFound( const QString& url, const QString& infoStr, const QString& version, const QString& edition)
|
|
||||||
{
|
|
||||||
Q_UNUSED(version);
|
|
||||||
Q_UNUSED(edition);
|
|
||||||
|
|
||||||
if( infoStr.isEmpty() ) {
|
|
||||||
} else {
|
|
||||||
// _ui.OCLabel->setText( tr("to your <a href=\"%1\">%2</a> (version %3)").arg(url)
|
|
||||||
// .arg(Theme::instance()->appNameGUI()).arg(infoStr));
|
|
||||||
_ui.OCFolderLineEdit->setEnabled( true );
|
|
||||||
qDebug() << "ownCloud found on " << url << " with version: " << infoStr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWizardTargetPage::slotNoOwnCloudFound( QNetworkReply* error )
|
void FolderWizardTargetPage::showWarn( const QString& msg ) const
|
||||||
{
|
{
|
||||||
qDebug() << "No ownCloud configured: " << error->error();
|
|
||||||
// _ui.OCLabel->setText( tr("no configured %1 found!").arg(Theme::instance()->appNameGUI()) );
|
|
||||||
showWarn( tr("%1 could not be reached:<br/><tt>%2</tt>")
|
|
||||||
.arg(Theme::instance()->appNameGUI()).arg(error->errorString()));
|
|
||||||
_ui.OCFolderLineEdit->setEnabled( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderWizardTargetPage::showWarn( const QString& msg, bool showCreateButton ) const
|
|
||||||
{
|
|
||||||
_ui._buttCreateFolder->setVisible( showCreateButton && !msg.isEmpty() );
|
|
||||||
|
|
||||||
if( msg.isEmpty() ) {
|
if( msg.isEmpty() ) {
|
||||||
_ui.warnFrame->hide();
|
_ui.warnFrame->hide();
|
||||||
|
|
||||||
@@ -332,34 +349,27 @@ void FolderWizardTargetPage::showWarn( const QString& msg, bool showCreateButton
|
|||||||
|
|
||||||
FolderWizard::FolderWizard( QWidget *parent )
|
FolderWizard::FolderWizard( QWidget *parent )
|
||||||
: QWizard(parent),
|
: QWizard(parent),
|
||||||
_folderWizardSourcePage(0),
|
_folderWizardSourcePage(new FolderWizardSourcePage),
|
||||||
_folderWizardTargetPage(0)
|
_folderWizardTargetPage(0)
|
||||||
{
|
{
|
||||||
_folderWizardSourcePage = new FolderWizardSourcePage();
|
setPage(Page_Source, _folderWizardSourcePage );
|
||||||
setPage(Page_Source, _folderWizardSourcePage );
|
|
||||||
if (!Theme::instance()->singleSyncFolder()) {
|
if (!Theme::instance()->singleSyncFolder()) {
|
||||||
_folderWizardTargetPage = new FolderWizardTargetPage();
|
_folderWizardTargetPage = new FolderWizardTargetPage();
|
||||||
setPage(Page_Target, _folderWizardTargetPage );
|
setPage(Page_Target, _folderWizardTargetPage );
|
||||||
}
|
}
|
||||||
|
|
||||||
setWindowTitle( tr( "%1 Folder Wizard" ).arg( Theme::instance()->appNameGUI() ) );
|
setWindowTitle( tr("Add Folder") );
|
||||||
#ifdef Q_WS_MAC
|
setOptions(QWizard::CancelButtonOnLeft);
|
||||||
setWizardStyle( QWizard::ModernStyle );
|
setButtonText(QWizard::FinishButton, tr("Add Folder"));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderWizard::~FolderWizard()
|
FolderWizard::~FolderWizard()
|
||||||
{
|
{
|
||||||
delete _folderWizardSourcePage;
|
|
||||||
if( _folderWizardTargetPage )
|
|
||||||
delete _folderWizardTargetPage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderWizard::setFolderMap( Folder::Map *fm)
|
void FolderWizard::setFolderMap( const Folder::Map& fm)
|
||||||
{
|
{
|
||||||
if( _folderWizardSourcePage ) {
|
|
||||||
_folderWizardSourcePage->setFolderMap( fm );
|
_folderWizardSourcePage->setFolderMap( fm );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|||||||
@@ -42,14 +42,14 @@ public:
|
|||||||
void initializePage();
|
void initializePage();
|
||||||
void cleanupPage();
|
void cleanupPage();
|
||||||
|
|
||||||
void setFolderMap( Folder::Map *fm ) { _folderMap = fm; }
|
void setFolderMap( const Folder::Map &fm ) { _folderMap = fm; }
|
||||||
protected slots:
|
protected slots:
|
||||||
void on_localFolderChooseBtn_clicked();
|
void on_localFolderChooseBtn_clicked();
|
||||||
void on_localFolderLineEdit_textChanged();
|
void on_localFolderLineEdit_textChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui_FolderWizardSourcePage _ui;
|
Ui_FolderWizardSourcePage _ui;
|
||||||
Folder::Map *_folderMap;
|
Folder::Map _folderMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -70,19 +70,16 @@ public:
|
|||||||
virtual void cleanupPage();
|
virtual void cleanupPage();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
|
|
||||||
void slotNoOwnCloudFound(QNetworkReply*);
|
|
||||||
|
|
||||||
void slotFolderTextChanged( const QString& );
|
void showWarn( const QString& = QString() ) const;
|
||||||
void slotTimerFires();
|
void slotAddRemoteFolder();
|
||||||
void slotDirCheckReply( const QString&, QNetworkReply* );
|
void slotCreateRemoteFolder(QString);
|
||||||
void showWarn( const QString& = QString(), bool showCreateButton = false ) const;
|
|
||||||
void slotCreateRemoteFolder();
|
|
||||||
void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError error );
|
void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError error );
|
||||||
|
void slotUpdateDirectories(QStringList);
|
||||||
|
void slotRefreshFolders();
|
||||||
|
void slotItemExpanded(QTreeWidgetItem*);
|
||||||
private:
|
private:
|
||||||
Ui_FolderWizardTargetPage _ui;
|
Ui_FolderWizardTargetPage _ui;
|
||||||
QTimer *_timer;
|
|
||||||
ownCloudInfo *_ownCloudDirCheck;
|
ownCloudInfo *_ownCloudDirCheck;
|
||||||
bool _dirChecked;
|
bool _dirChecked;
|
||||||
bool _warnWasVisible;
|
bool _warnWasVisible;
|
||||||
@@ -103,7 +100,7 @@ public:
|
|||||||
|
|
||||||
FolderWizard(QWidget *parent = 0);
|
FolderWizard(QWidget *parent = 0);
|
||||||
~FolderWizard();
|
~FolderWizard();
|
||||||
void setFolderMap( Folder::Map* );
|
void setFolderMap( const Folder::Map &map );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -7,29 +7,30 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>423</width>
|
<width>423</width>
|
||||||
<height>226</height>
|
<height>155</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_3">
|
<spacer name="verticalSpacer">
|
||||||
<property name="font">
|
<property name="orientation">
|
||||||
<font>
|
<enum>Qt::Vertical</enum>
|
||||||
<pointsize>14</pointsize>
|
|
||||||
</font>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="sizeHint" stdset="0">
|
||||||
<string>Sync Directory</string>
|
<size>
|
||||||
|
<width>349</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Pick a local folder on your computer to sync:</string>
|
<string>Pick a local folder on your computer to sync</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="warnLabel">
|
<widget class="QLabel" name="warnLabel">
|
||||||
<property name="palette">
|
<property name="palette">
|
||||||
<palette>
|
<palette>
|
||||||
@@ -152,19 +153,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>349</width>
|
|
||||||
<height>83</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
@@ -7,93 +7,14 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>520</width>
|
<width>520</width>
|
||||||
<height>367</height>
|
<height>300</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_6">
|
<layout class="QGridLayout" name="gridLayout_6">
|
||||||
<item row="0" column="0">
|
<item row="3" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>14</pointsize>
|
|
||||||
<weight>50</weight>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Synchronization Target</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_17">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Select a destination folder</string>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QFrame" name="frame">
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::StyledPanel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="frameShadow">
|
|
||||||
<enum>QFrame::Raised</enum>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0" rowspan="2">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string>Remote folder:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="OCFolderLineEdit"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QFrame" name="warnFrame">
|
<widget class="QFrame" name="warnFrame">
|
||||||
<property name="palette">
|
<property name="palette">
|
||||||
<palette>
|
<palette>
|
||||||
@@ -191,30 +112,77 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="margin">
|
<property name="margin">
|
||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="_buttCreateFolder">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>create</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="0" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Select a destination folder</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QPushButton" name="addFolderButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Folder</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="refreshButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Refresh</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" rowspan="4">
|
||||||
|
<widget class="QTreeWidget" name="folderTreeWidget">
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Folders</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@@ -222,7 +190,7 @@
|
|||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>20</width>
|
<width>20</width>
|
||||||
<height>102</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
|
|||||||
97
src/mirall/generalsettings.cpp
Normal file
97
src/mirall/generalsettings.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "generalsettings.h"
|
||||||
|
#include "ui_generalsettings.h"
|
||||||
|
|
||||||
|
#include "mirall/theme.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
#include "mirall/application.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
#include <QNetworkProxy>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
_ui(new Ui::GeneralSettings)
|
||||||
|
{
|
||||||
|
_ui->setupUi(this);
|
||||||
|
|
||||||
|
connect(_ui->desktopNotificationsCheckBox, SIGNAL(toggled(bool)),
|
||||||
|
SLOT(slotToggleOptionalDesktopNotifications(bool)));
|
||||||
|
|
||||||
|
_ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName()));
|
||||||
|
connect(_ui->autostartCheckBox, SIGNAL(toggled(bool)), SLOT(slotToggleLaunchOnStartup(bool)));
|
||||||
|
|
||||||
|
// setup about section
|
||||||
|
QString about = Theme::instance()->about();
|
||||||
|
if (about.isEmpty()) {
|
||||||
|
_ui->aboutGroupBox->hide();
|
||||||
|
} else {
|
||||||
|
_ui->aboutLabel->setText(about);
|
||||||
|
_ui->aboutLabel->setOpenExternalLinks(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadMiscSettings();
|
||||||
|
|
||||||
|
// misc
|
||||||
|
connect(_ui->monoIconsCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||||
|
|
||||||
|
// OEM themes are not obliged to ship mono icons, so there
|
||||||
|
// is no point in offering an option
|
||||||
|
QString themeDir = QString::fromLatin1(":/mirall/theme/1%1/")
|
||||||
|
.arg(Theme::instance()->systrayIconFlavor(true));
|
||||||
|
if (QDir(themeDir).exists())
|
||||||
|
{
|
||||||
|
_ui->monoIconsCheckBox->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralSettings::~GeneralSettings()
|
||||||
|
{
|
||||||
|
delete _ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralSettings::loadMiscSettings()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||||
|
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralSettings::saveMiscSettings()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
bool isChecked = _ui->monoIconsCheckBox->isChecked();
|
||||||
|
cfgFile.setMonoIcons(isChecked);
|
||||||
|
Theme::instance()->setSystrayUseMonoIcons(isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
|
||||||
|
{
|
||||||
|
Theme *theme = Theme::instance();
|
||||||
|
Utility::setLaunchOnStartup(theme->appName(), theme->appNameGUI(), enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneralSettings::slotToggleOptionalDesktopNotifications(bool enable)
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
cfgFile.setOptionalDesktopNotifications(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
50
src/mirall/generalsettings.h
Normal file
50
src/mirall/generalsettings.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_GENERALSETTINGS_H
|
||||||
|
#define MIRALL_GENERALSETTINGS_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class GeneralSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeneralSettings : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GeneralSettings(QWidget *parent = 0);
|
||||||
|
~GeneralSettings();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void proxySettingsChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void saveMiscSettings();
|
||||||
|
void slotToggleLaunchOnStartup(bool);
|
||||||
|
void slotToggleOptionalDesktopNotifications(bool);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadMiscSettings();
|
||||||
|
|
||||||
|
Ui::GeneralSettings *_ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
#endif // MIRALL_GENERALSETTINGS_H
|
||||||
83
src/mirall/generalsettings.ui
Normal file
83
src/mirall/generalsettings.ui
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Mirall::GeneralSettings</class>
|
||||||
|
<widget class="QWidget" name="Mirall::GeneralSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>468</width>
|
||||||
|
<height>169</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="generalGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QCheckBox" name="autostartCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Launch on System Startup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QCheckBox" name="desktopNotificationsCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Desktop Notifications</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QCheckBox" name="monoIconsCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Monochrome Icons</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="aboutGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="aboutLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
<buttongroups>
|
||||||
|
<buttongroup name="proxyButtonGroup"/>
|
||||||
|
</buttongroups>
|
||||||
|
</ui>
|
||||||
167
src/mirall/ignorelisteditor.cpp
Normal file
167
src/mirall/ignorelisteditor.cpp
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
#include "ignorelisteditor.h"
|
||||||
|
#include "ui_ignorelisteditor.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QColorGroup>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QInputDialog>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
IgnoreListEditor::IgnoreListEditor(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::IgnoreListEditor)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->descriptionLabel->setText(tr("Files or directories matching a pattern will not be synchronized.\n\n"
|
||||||
|
"Checked items will also be deleted if they prevent a directory from "
|
||||||
|
"being removed. This is useful for meta data."));
|
||||||
|
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::SystemScope), true);
|
||||||
|
readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::UserScope), false);
|
||||||
|
|
||||||
|
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
|
||||||
|
ui->removePushButton->setEnabled(false);
|
||||||
|
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
|
||||||
|
connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemChanged(QListWidgetItem*)));
|
||||||
|
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
|
||||||
|
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
|
||||||
|
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupItemFlags(QListWidgetItem* item)
|
||||||
|
{
|
||||||
|
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
IgnoreListEditor::~IgnoreListEditor()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::slotItemSelectionChanged()
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->listWidget->currentItem();
|
||||||
|
if (!item) {
|
||||||
|
ui->removePushButton->setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enable = item->flags() & Qt::ItemIsEnabled;
|
||||||
|
ui->removePushButton->setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::slotRemoveCurrentItem()
|
||||||
|
{
|
||||||
|
delete ui->listWidget->currentItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::slotUpdateLocalIgnoreList()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
QString ignoreFile = cfgFile.excludeFile(MirallConfigFile::UserScope);
|
||||||
|
QFile ignores(ignoreFile);
|
||||||
|
if (ignores.open(QIODevice::WriteOnly)) {
|
||||||
|
for(int i = 0; i < ui->listWidget->count(); ++i) {
|
||||||
|
QListWidgetItem *item = ui->listWidget->item(i);
|
||||||
|
if (item->flags() & Qt::ItemIsEnabled) {
|
||||||
|
QByteArray prepend;
|
||||||
|
if (item->checkState() == Qt::Checked) {
|
||||||
|
prepend = "]";
|
||||||
|
}
|
||||||
|
ignores.write(prepend+item->text().toUtf8()+'\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, tr("Could not open file"),
|
||||||
|
tr("Cannot write changes to '%1'.").arg(ignoreFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::slotAddPattern()
|
||||||
|
{
|
||||||
|
bool okClicked;
|
||||||
|
QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"),
|
||||||
|
tr("Add a new ignore pattern:"),
|
||||||
|
QLineEdit::Normal, QString(), &okClicked);
|
||||||
|
|
||||||
|
if (!okClicked || pattern.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QListWidgetItem *item = new QListWidgetItem;
|
||||||
|
setupItemFlags(item);
|
||||||
|
if (pattern.startsWith("]")) {
|
||||||
|
pattern = pattern.mid(1);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
|
}
|
||||||
|
item->setText(pattern);
|
||||||
|
ui->listWidget->addItem(item);
|
||||||
|
ui->listWidget->scrollToItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::slotEditPattern(QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
if (!(item->flags() & Qt::ItemIsEnabled))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"),
|
||||||
|
tr("Add a new ignore pattern:"),
|
||||||
|
QLineEdit::Normal, item->text());
|
||||||
|
if (!pattern.isEmpty()) {
|
||||||
|
item->setText(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IgnoreListEditor::readIgnoreFile(const QString &file, bool readOnly)
|
||||||
|
{
|
||||||
|
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
const QString disabledTip(tr("This entry is provided by the system at '%1' "
|
||||||
|
"and cannot be modified in this view.")
|
||||||
|
.arg(QDir::toNativeSeparators(cfgFile.excludeFile(MirallConfigFile::SystemScope))));
|
||||||
|
|
||||||
|
QFile ignores(file);
|
||||||
|
if (ignores.open(QIODevice::ReadOnly)) {
|
||||||
|
while (!ignores.atEnd()) {
|
||||||
|
QString line = QString::fromUtf8(ignores.readLine());
|
||||||
|
line.chop(1);
|
||||||
|
if (!line.isEmpty() && !line.startsWith("#")) {
|
||||||
|
QListWidgetItem *item = new QListWidgetItem;
|
||||||
|
setupItemFlags(item);
|
||||||
|
if (line.startsWith("]")) {
|
||||||
|
line = line.mid(1);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
|
}
|
||||||
|
item->setText(line);
|
||||||
|
if (readOnly) {
|
||||||
|
item->setFlags(item->flags() ^ Qt::ItemIsEnabled);
|
||||||
|
item->setToolTip(disabledTip);
|
||||||
|
}
|
||||||
|
ui->listWidget->addItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
49
src/mirall/ignorelisteditor.h
Normal file
49
src/mirall/ignorelisteditor.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IGNORELISTEDITOR_H
|
||||||
|
#define IGNORELISTEDITOR_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class IgnoreListEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
class IgnoreListEditor : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit IgnoreListEditor(QWidget *parent = 0);
|
||||||
|
~IgnoreListEditor();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotItemSelectionChanged();
|
||||||
|
void slotRemoveCurrentItem();
|
||||||
|
void slotUpdateLocalIgnoreList();
|
||||||
|
void slotAddPattern();
|
||||||
|
void slotEditPattern(QListWidgetItem*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readIgnoreFile(const QString& file, bool readOnly);
|
||||||
|
Ui::IgnoreListEditor *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
|
||||||
|
#endif // IGNORELISTEDITOR_H
|
||||||
117
src/mirall/ignorelisteditor.ui
Normal file
117
src/mirall/ignorelisteditor.ui
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Mirall::IgnoreListEditor</class>
|
||||||
|
<widget class="QDialog" name="Mirall::IgnoreListEditor">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>471</width>
|
||||||
|
<height>359</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Ignored Files Editor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="5" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>213</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" rowspan="3">
|
||||||
|
<widget class="QListWidget" name="listWidget">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QPushButton" name="addPushButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="removePushButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="descriptionLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Mirall::IgnoreListEditor</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>348</x>
|
||||||
|
<y>333</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>361</x>
|
||||||
|
<y>355</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Mirall::IgnoreListEditor</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>210</x>
|
||||||
|
<y>333</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>385</x>
|
||||||
|
<y>297</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -47,7 +47,7 @@ INotify::INotify(QObject *parent, int mask)
|
|||||||
_buffer = (char *) malloc(_buffer_size);
|
_buffer = (char *) malloc(_buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void INotify::slotActivated(int fd)
|
void INotify::slotActivated(int /*fd*/)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
struct inotify_event* event;
|
struct inotify_event* event;
|
||||||
@@ -82,7 +82,7 @@ void INotify::slotActivated(int fd)
|
|||||||
// reset counter
|
// reset counter
|
||||||
i = 0;
|
i = 0;
|
||||||
// while there are enough events in the buffer
|
// while there are enough events in the buffer
|
||||||
while(i + sizeof(struct inotify_event) < len) {
|
while(i + sizeof(struct inotify_event) < static_cast<unsigned int>(len)) {
|
||||||
// cast an inotify_event
|
// cast an inotify_event
|
||||||
event = (struct inotify_event*)&_buffer[i];
|
event = (struct inotify_event*)&_buffer[i];
|
||||||
// with the help of watch descriptor, retrieve, corresponding INotify
|
// with the help of watch descriptor, retrieve, corresponding INotify
|
||||||
@@ -115,14 +115,17 @@ INotify::~INotify()
|
|||||||
delete _notifier;
|
delete _notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
void INotify::addPath(const QString &path)
|
bool INotify::addPath(const QString &path)
|
||||||
{
|
{
|
||||||
// Add an inotify watch.
|
// Add an inotify watch.
|
||||||
int wd = inotify_add_watch(_fd, path.toUtf8().constData(), _mask);
|
int wd = inotify_add_watch(_fd, path.toUtf8().constData(), _mask);
|
||||||
if( wd > -1 )
|
if( wd > -1 ) {
|
||||||
_wds[path] = wd;
|
_wds[path] = wd;
|
||||||
else
|
return true;
|
||||||
|
} else {
|
||||||
qDebug() << "WRN: Could not watch " << path << ':' << strerror(errno);
|
qDebug() << "WRN: Could not watch " << path << ':' << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void INotify::removePath(const QString &path)
|
void INotify::removePath(const QString &path)
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ public:
|
|||||||
INotify(QObject *parent, int mask);
|
INotify(QObject *parent, int mask);
|
||||||
~INotify();
|
~INotify();
|
||||||
|
|
||||||
static void initialize();
|
bool addPath(const QString &name);
|
||||||
static void cleanup();
|
|
||||||
|
|
||||||
void addPath(const QString &name);
|
|
||||||
void removePath(const QString &name);
|
void removePath(const QString &name);
|
||||||
|
|
||||||
QStringList directories() const;
|
QStringList directories() const;
|
||||||
|
|||||||
311
src/mirall/itemprogressdialog.cpp
Normal file
311
src/mirall/itemprogressdialog.cpp
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
#include "mirall/itemprogressdialog.h"
|
||||||
|
#include "mirall/syncresult.h"
|
||||||
|
#include "mirall/logger.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/theme.h"
|
||||||
|
#include "mirall/folderman.h"
|
||||||
|
#include "mirall/syncfileitem.h"
|
||||||
|
|
||||||
|
#include "ui_itemprogressdialog.h"
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
ItemProgressDialog::ItemProgressDialog(Application*, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ErrorIndicatorRole( Qt::UserRole +1 ),
|
||||||
|
_ui(new Ui::ItemProgressDialog)
|
||||||
|
{
|
||||||
|
_ui->setupUi(this);
|
||||||
|
connect(_ui->_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
|
||||||
|
this, SLOT(accept()));
|
||||||
|
|
||||||
|
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,Progress::Info)),
|
||||||
|
this, SLOT(slotProgressInfo(QString,Progress::Info)));
|
||||||
|
connect(ProgressDispatcher::instance(), SIGNAL(progressSyncProblem(const QString&,const Progress::SyncProblem&)),
|
||||||
|
this, SLOT(slotProgressErrors(const QString&, const Progress::SyncProblem&)));
|
||||||
|
|
||||||
|
QStringList header;
|
||||||
|
header << tr("Time");
|
||||||
|
header << tr("File");
|
||||||
|
header << tr("Folder");
|
||||||
|
header << tr("Action");
|
||||||
|
header << tr("Size");
|
||||||
|
|
||||||
|
_ui->_treeWidget->setHeaderLabels( header );
|
||||||
|
_ui->_treeWidget->setColumnWidth(1, 180);
|
||||||
|
_ui->_treeWidget->setColumnCount(5);
|
||||||
|
_ui->_treeWidget->setRootIsDecorated(false);
|
||||||
|
|
||||||
|
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
||||||
|
|
||||||
|
QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
||||||
|
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
|
||||||
|
|
||||||
|
setWindowTitle(tr("Sync Protocol"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::setSyncResultStatus(const SyncResult& result )
|
||||||
|
{
|
||||||
|
if( result.errorStrings().count() ) {
|
||||||
|
_ui->_errorLabel->setVisible(true);
|
||||||
|
_ui->_errorLabel->setTextFormat(Qt::RichText);
|
||||||
|
|
||||||
|
QString errStr;
|
||||||
|
QStringList errors = result.errorStrings();
|
||||||
|
int cnt = errors.size();
|
||||||
|
bool appendDots = false;
|
||||||
|
if( cnt > 3 ) {
|
||||||
|
cnt = 3;
|
||||||
|
appendDots = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0; i < cnt; i++) {
|
||||||
|
errStr.append(QString("%1<br/>").arg(errors.at(i)));
|
||||||
|
}
|
||||||
|
if( appendDots ) {
|
||||||
|
errStr.append(QString("..."));
|
||||||
|
}
|
||||||
|
_ui->_errorLabel->setText(errStr);
|
||||||
|
} else {
|
||||||
|
_ui->_errorLabel->setText(QString::null);
|
||||||
|
_ui->_errorLabel->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::setSyncResult( const SyncResult& result )
|
||||||
|
{
|
||||||
|
setSyncResultStatus(result);
|
||||||
|
|
||||||
|
const QString& folder = result.folder();
|
||||||
|
qDebug() << "Setting sync result for folder " << folder;
|
||||||
|
|
||||||
|
SyncFileItemVector::const_iterator i;
|
||||||
|
const SyncFileItemVector& items = result.syncFileItemVector();
|
||||||
|
QDateTime dt = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
for (i = items.begin(); i != items.end(); ++i) {
|
||||||
|
const SyncFileItem& item = *i;
|
||||||
|
QString errMsg;
|
||||||
|
// handle ignored files here.
|
||||||
|
if( item._instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||||
|
QStringList columns;
|
||||||
|
QString timeStr = timeString(dt);
|
||||||
|
QString longTimeStr = timeString(dt, QLocale::LongFormat);
|
||||||
|
|
||||||
|
columns << timeStr;
|
||||||
|
columns << item._file;
|
||||||
|
columns << folder;
|
||||||
|
if( item._type == SyncFileItem::File ) {
|
||||||
|
errMsg = tr("File ignored.");
|
||||||
|
} else if( item._type == SyncFileItem::Directory ){
|
||||||
|
errMsg = tr("Directory ignored.");
|
||||||
|
} else if( item._type == SyncFileItem::SoftLink ) {
|
||||||
|
errMsg = tr("Soft Link ignored.");
|
||||||
|
} else {
|
||||||
|
errMsg = tr("Ignored.");
|
||||||
|
}
|
||||||
|
columns << errMsg;
|
||||||
|
|
||||||
|
QTreeWidgetItem *twitem = new QTreeWidgetItem(columns);
|
||||||
|
twitem->setData(0, ErrorIndicatorRole, QVariant(true) );
|
||||||
|
twitem->setToolTip(0, longTimeStr);
|
||||||
|
twitem->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Problem, true));
|
||||||
|
_ui->_treeWidget->addTopLevelItem(twitem);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::setupList()
|
||||||
|
{
|
||||||
|
// get the folders to set up the top level list.
|
||||||
|
Folder::Map map = FolderMan::instance()->map();
|
||||||
|
SyncResult lastResult;
|
||||||
|
QDateTime dt;
|
||||||
|
bool haveSyncResult = false;
|
||||||
|
|
||||||
|
foreach( Folder *f, map.values() ) {
|
||||||
|
if( f->syncResult().syncTime() > dt ) {
|
||||||
|
dt = f->syncResult().syncTime();
|
||||||
|
lastResult = f->syncResult();
|
||||||
|
haveSyncResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( haveSyncResult ) {
|
||||||
|
setSyncResult(lastResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Progress::Info> progressList = ProgressDispatcher::instance()->recentChangedItems(0); // All.
|
||||||
|
|
||||||
|
QHash <QString, int> folderHash;
|
||||||
|
|
||||||
|
foreach( Progress::Info info, progressList ) {
|
||||||
|
slotProgressInfo( info.folder, info );
|
||||||
|
folderHash[info.folder] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Progress::SyncProblem> problemList = ProgressDispatcher::instance()->recentProblems(0);
|
||||||
|
foreach( Progress::SyncProblem prob, problemList ) {
|
||||||
|
slotProgressErrors(prob.folder, prob);
|
||||||
|
folderHash[prob.folder] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemProgressDialog::~ItemProgressDialog()
|
||||||
|
{
|
||||||
|
delete _ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::copyToClipboard()
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
QTextStream ts(&text);
|
||||||
|
|
||||||
|
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
|
||||||
|
for (int i = 0; i < topLevelItems; i++) {
|
||||||
|
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(i);
|
||||||
|
ts << left << qSetFieldWidth(0)
|
||||||
|
<< item->data(0, Qt::DisplayRole).toString()
|
||||||
|
<< endl;
|
||||||
|
int childItems = item->childCount();
|
||||||
|
for (int j = 0; j < childItems; j++) {
|
||||||
|
QTreeWidgetItem *child =item->child(j);
|
||||||
|
// time stamp
|
||||||
|
ts << left << qSetFieldWidth(10)
|
||||||
|
<< child->data(0,Qt::DisplayRole).toString()
|
||||||
|
// file name
|
||||||
|
<< qSetFieldWidth(50)
|
||||||
|
<< child->data(1,Qt::DisplayRole).toString()
|
||||||
|
// action
|
||||||
|
<< qSetFieldWidth(15)
|
||||||
|
<< child->data(2, Qt::DisplayRole).toString()
|
||||||
|
// size
|
||||||
|
<< qSetFieldWidth(10)
|
||||||
|
<< child->data(3, Qt::DisplayRole).toString()
|
||||||
|
<< qSetFieldWidth(0)
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QApplication::clipboard()->setText(text);
|
||||||
|
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::accept()
|
||||||
|
{
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::cleanErrors( const QString& /* folder */ ) // FIXME: Use the folder to detect which errors can be deleted.
|
||||||
|
{
|
||||||
|
_problemCounter = 0;
|
||||||
|
QList<QTreeWidgetItem*> wipeList;
|
||||||
|
|
||||||
|
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
||||||
|
|
||||||
|
for( int cnt = 0; cnt < itemCnt; cnt++ ) {
|
||||||
|
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
|
||||||
|
bool isErrorItem = item->data(0, ErrorIndicatorRole).toBool();
|
||||||
|
if( isErrorItem ) {
|
||||||
|
wipeList.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDeleteAll(wipeList.begin(), wipeList.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ItemProgressDialog::timeString(QDateTime dt, QLocale::FormatType format) const
|
||||||
|
{
|
||||||
|
QLocale loc = QLocale::system();
|
||||||
|
QString timeStr;
|
||||||
|
QDate today = QDate::currentDate();
|
||||||
|
|
||||||
|
if( format == QLocale::NarrowFormat ) {
|
||||||
|
if( dt.date().day() == today.day() ) {
|
||||||
|
timeStr = loc.toString(dt.time(), QLocale::NarrowFormat);
|
||||||
|
} else {
|
||||||
|
timeStr = loc.toString(dt, QLocale::NarrowFormat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeStr = loc.toString(dt, format);
|
||||||
|
}
|
||||||
|
return timeStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem )
|
||||||
|
{
|
||||||
|
QStringList columns;
|
||||||
|
QString timeStr = timeString(problem.timestamp);
|
||||||
|
QString longTimeStr = timeString(problem.timestamp, QLocale::LongFormat);
|
||||||
|
|
||||||
|
columns << timeStr;
|
||||||
|
columns << problem.current_file;
|
||||||
|
columns << folder;
|
||||||
|
QString errMsg = tr("Problem: %1").arg(problem.error_message);
|
||||||
|
#if 0
|
||||||
|
if( problem.error_code == 507 ) {
|
||||||
|
errMsg = tr("No more storage space available on server.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
columns << errMsg;
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(columns);
|
||||||
|
item->setData(0, ErrorIndicatorRole, QVariant(true) );
|
||||||
|
// Maybe we should not set the error icon for all problems but distinguish
|
||||||
|
// by error_code. A quota problem is considered an error, others might not??
|
||||||
|
item->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Error, true));
|
||||||
|
item->setToolTip(0, longTimeStr);
|
||||||
|
_ui->_treeWidget->addTopLevelItem(item);
|
||||||
|
Q_UNUSED(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemProgressDialog::slotProgressInfo( const QString& folder, const Progress::Info& progress )
|
||||||
|
{
|
||||||
|
if( progress.kind == Progress::StartSync ) {
|
||||||
|
cleanErrors( folder );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( progress.kind == Progress::EndSync ) {
|
||||||
|
// decorateFolderItem( folder );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ingore other events than finishing an individual up- or download.
|
||||||
|
if( !(progress.kind == Progress::EndDownload || progress.kind == Progress::EndUpload || progress.kind == Progress::EndDelete)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList columns;
|
||||||
|
QString timeStr = timeString(progress.timestamp);
|
||||||
|
QString longTimeStr = timeString(progress.timestamp, QLocale::LongFormat);
|
||||||
|
|
||||||
|
columns << timeStr;
|
||||||
|
columns << progress.current_file;
|
||||||
|
columns << progress.folder;
|
||||||
|
columns << Progress::asResultString(progress.kind);
|
||||||
|
columns << Utility::octetsToString( progress.file_size );
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(columns);
|
||||||
|
item->setToolTip(0, longTimeStr);
|
||||||
|
_ui->_treeWidget->addTopLevelItem(item);
|
||||||
|
Q_UNUSED(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,52 +16,51 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QTimer>
|
#include <QLocale>
|
||||||
|
|
||||||
#include "mirall/syncfileitem.h"
|
#include "mirall/progressdispatcher.h"
|
||||||
|
|
||||||
#include "ui_fileitemdialog.h"
|
#include "ui_itemprogressdialog.h"
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
class Theme;
|
|
||||||
class SyncResult;
|
class SyncResult;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ItemProgressDialog;
|
||||||
|
}
|
||||||
|
class Application;
|
||||||
|
|
||||||
class FileItemDialog : public QDialog, public Ui::_fileItemDialog
|
class ItemProgressDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit FileItemDialog(Theme*, QWidget *parent = 0);
|
explicit ItemProgressDialog(Application *app, QWidget *parent = 0);
|
||||||
void setSyncResult( const SyncResult& );
|
~ItemProgressDialog();
|
||||||
|
|
||||||
|
void setupList();
|
||||||
|
void setSyncResult( const SyncResult& result );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void accept();
|
void accept();
|
||||||
|
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
|
||||||
|
void slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem );
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotSetFolderMessage();
|
|
||||||
void copyToClipboard();
|
void copyToClipboard();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void guiLog(const QString&, const QString&);
|
void guiLog(const QString&, const QString&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setSyncFileItems( const SyncFileItemVector& list );
|
void setSyncResultStatus(const SyncResult& result );
|
||||||
void formatHeaderItem( QTreeWidgetItem *, const QList<QTreeWidgetItem*>& );
|
void cleanErrors( const QString& folder );
|
||||||
|
QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat) const;
|
||||||
|
|
||||||
QTreeWidgetItem *_newFileItem;
|
const int ErrorIndicatorRole;
|
||||||
QTreeWidgetItem *_syncedFileItem;
|
Ui::ItemProgressDialog *_ui;
|
||||||
QTreeWidgetItem *_deletedFileItem;
|
int _problemCounter;
|
||||||
QTreeWidgetItem *_renamedFileItem;
|
|
||||||
QTreeWidgetItem *_errorFileItem;
|
|
||||||
QTreeWidgetItem *_conflictFileItem;
|
|
||||||
QTreeWidgetItem *_ignoredFileItem;
|
|
||||||
|
|
||||||
Theme *_theme;
|
|
||||||
QString _folderMessage;
|
|
||||||
QDateTime _lastSyncTime;
|
|
||||||
QTimer _timer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>_fileItemDialog</class>
|
<class>Mirall::ItemProgressDialog</class>
|
||||||
<widget class="QWidget" name="_fileItemDialog">
|
<widget class="QWidget" name="Mirall::ItemProgressDialog">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="columnCount">
|
<property name="columnCount">
|
||||||
<number>2</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -55,13 +55,16 @@
|
|||||||
<string notr="true">2</string>
|
<string notr="true">2</string>
|
||||||
</property>
|
</property>
|
||||||
</column>
|
</column>
|
||||||
</widget>
|
<column>
|
||||||
</item>
|
<property name="text">
|
||||||
<item>
|
<string>3</string>
|
||||||
<widget class="QLabel" name="_timelabel">
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>TextLabel</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/logger.h"
|
#include "mirall/logger.h"
|
||||||
@@ -44,11 +46,6 @@ LogWidget::LogWidget(QWidget *parent)
|
|||||||
font.setFamily(QLatin1String("Courier New"));
|
font.setFamily(QLatin1String("Courier New"));
|
||||||
font.setFixedPitch(true);
|
font.setFixedPitch(true);
|
||||||
document()->setDefaultFont( font );
|
document()->setDefaultFont( font );
|
||||||
|
|
||||||
MirallConfigFile cfg;
|
|
||||||
int lines = cfg.maxLogLines();
|
|
||||||
// qDebug() << "# ## Have " << lines << " Loglines!";
|
|
||||||
document()->setMaximumBlockCount( lines );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
@@ -56,9 +53,9 @@ LogWidget::LogWidget(QWidget *parent)
|
|||||||
LogBrowser::LogBrowser(QWidget *parent) :
|
LogBrowser::LogBrowser(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
_logWidget( new LogWidget(parent) ),
|
_logWidget( new LogWidget(parent) ),
|
||||||
_logstream(0),
|
|
||||||
_doFileFlush(false)
|
_doFileFlush(false)
|
||||||
{
|
{
|
||||||
|
setObjectName("LogBrowser"); // for save/restoreGeometry()
|
||||||
setWindowTitle(tr("Log Output"));
|
setWindowTitle(tr("Log Output"));
|
||||||
setMinimumWidth(600);
|
setMinimumWidth(600);
|
||||||
|
|
||||||
@@ -115,6 +112,18 @@ LogBrowser::LogBrowser(QWidget *parent) :
|
|||||||
|
|
||||||
// Direct connection for log comming from this thread, and queued for the one in a different thread
|
// Direct connection for log comming from this thread, and queued for the one in a different thread
|
||||||
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
||||||
|
|
||||||
|
QAction *showLogWindow = new QAction(this);
|
||||||
|
showLogWindow->setShortcut(QKeySequence("F12"));
|
||||||
|
connect(showLogWindow, SIGNAL(triggered()), SLOT(close()));
|
||||||
|
addAction(showLogWindow);
|
||||||
|
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
cfg.restoreGeometry(this);
|
||||||
|
int lines = cfg.maxLogLines();
|
||||||
|
// qDebug() << "# ## Have " << lines << " Loglines!";
|
||||||
|
_logWidget->document()->setMaximumBlockCount( lines );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogBrowser::~LogBrowser()
|
LogBrowser::~LogBrowser()
|
||||||
@@ -123,9 +132,7 @@ LogBrowser::~LogBrowser()
|
|||||||
|
|
||||||
void LogBrowser::slotNewLog( const QString& msg )
|
void LogBrowser::slotNewLog( const QString& msg )
|
||||||
{
|
{
|
||||||
if( _logWidget->isVisible() ) {
|
_logWidget->appendPlainText( msg );
|
||||||
_logWidget->appendPlainText( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _logstream ) {
|
if( _logstream ) {
|
||||||
(*_logstream) << msg << endl;
|
(*_logstream) << msg << endl;
|
||||||
@@ -138,9 +145,16 @@ void LogBrowser::setLogFile( const QString & name, bool flush )
|
|||||||
if( _logstream ) {
|
if( _logstream ) {
|
||||||
_logFile.close();
|
_logFile.close();
|
||||||
}
|
}
|
||||||
_logFile.setFileName( name );
|
|
||||||
|
|
||||||
if(!_logFile.open(QIODevice::WriteOnly)) {
|
bool openSucceeded = false;
|
||||||
|
if (name == QLatin1String("-")) {
|
||||||
|
openSucceeded = _logFile.open(1, QIODevice::WriteOnly);
|
||||||
|
} else {
|
||||||
|
_logFile.setFileName( name );
|
||||||
|
openSucceeded = _logFile.open(QIODevice::WriteOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!openSucceeded) {
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(
|
||||||
this,
|
this,
|
||||||
tr("Error"),
|
tr("Error"),
|
||||||
@@ -211,4 +225,11 @@ void LogBrowser::slotClearLog()
|
|||||||
_logWidget->clear();
|
_logWidget->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogBrowser::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
MirallConfigFile cfg;
|
||||||
|
cfg.saveGeometry(this);
|
||||||
|
QWidget::closeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -47,9 +47,8 @@ public:
|
|||||||
|
|
||||||
void setLogFile(const QString& , bool );
|
void setLogFile(const QString& , bool );
|
||||||
|
|
||||||
signals:
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
public slots:
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotNewLog( const QString &msg );
|
void slotNewLog( const QString &msg );
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ Logger::Logger( QObject* parent)
|
|||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
_showTime(true)
|
_showTime(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger *Logger::instance()
|
Logger *Logger::instance()
|
||||||
@@ -39,6 +38,21 @@ void Logger::destroy()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::postGuiLog(const QString &title, const QString &message)
|
||||||
|
{
|
||||||
|
emit guiLog(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::postOptionalGuiLog(const QString &title, const QString &message)
|
||||||
|
{
|
||||||
|
emit optionalGuiLog(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::postGuiMessage(const QString &title, const QString &message)
|
||||||
|
{
|
||||||
|
emit postGuiMessage(title, message);
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::log(Log log)
|
void Logger::log(Log log)
|
||||||
{
|
{
|
||||||
QString msg;
|
QString msg;
|
||||||
|
|||||||
@@ -46,9 +46,15 @@ public:
|
|||||||
static Logger* instance();
|
static Logger* instance();
|
||||||
static void destroy();
|
static void destroy();
|
||||||
|
|
||||||
|
void postGuiLog(const QString& title, const QString& message);
|
||||||
|
void postOptionalGuiLog(const QString& title, const QString& message);
|
||||||
|
void postGuiMessage(const QString& title, const QString& message);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newLog(const QString&);
|
void newLog(const QString&);
|
||||||
void guiLog(const QString&, const QString&);
|
void guiLog(const QString&, const QString&);
|
||||||
|
void guiMessage(const QString&, const QString&);
|
||||||
|
void optionalGuiLog(const QString&, const QString&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Logger(QObject* parent=0);
|
Logger(QObject* parent=0);
|
||||||
|
|||||||
34
src/mirall/mirallaccessmanager.cpp
Normal file
34
src/mirall/mirallaccessmanager.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
MirallAccessManager::MirallAccessManager(QObject* parent)
|
||||||
|
: QNetworkAccessManager (parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
|
||||||
|
{
|
||||||
|
QNetworkRequest newRequest(request);
|
||||||
|
|
||||||
|
newRequest.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString());
|
||||||
|
return QNetworkAccessManager::createRequest (op, newRequest, outgoingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
35
src/mirall/mirallaccessmanager.h
Normal file
35
src/mirall/mirallaccessmanager.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_ACCESS_MANAGER_H
|
||||||
|
#define MIRALL_ACCESS_MANAGER_H
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
|
namespace Mirall
|
||||||
|
{
|
||||||
|
|
||||||
|
class MirallAccessManager : public QNetworkAccessManager
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MirallAccessManager(QObject* parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,97 +18,192 @@
|
|||||||
#include "mirall/owncloudinfo.h"
|
#include "mirall/owncloudinfo.h"
|
||||||
#include "mirall/owncloudtheme.h"
|
#include "mirall/owncloudtheme.h"
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
#include "mirall/credentialstore.h"
|
#include "creds/abstractcredentials.h"
|
||||||
|
#include "creds/credentialsfactory.h"
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
|
|
||||||
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
|
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
|
||||||
|
#define DEFAULT_MAX_LOG_LINES 20000
|
||||||
#define CA_CERTS_KEY QLatin1String("CaCertificates")
|
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
|
static const char urlC[] = "url";
|
||||||
|
static const char authTypeC[] = "authType";
|
||||||
|
|
||||||
|
static const char caCertsKeyC[] = "CaCertificates";
|
||||||
|
static const char remotePollIntervalC[] = "remotePollInterval";
|
||||||
|
static const char forceSyncIntervalC[] = "forceSyncInterval";
|
||||||
|
static const char monoIconsC[] = "monoIcons";
|
||||||
|
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
|
||||||
|
static const char skipUpdateCheckC[] = "skipUpdateCheck";
|
||||||
|
static const char geometryC[] = "geometry";
|
||||||
|
|
||||||
|
static const char proxyHostC[] = "Proxy/host";
|
||||||
|
static const char proxyTypeC[] = "Proxy/type";
|
||||||
|
static const char proxyPortC[] = "Proxy/port";
|
||||||
|
static const char proxyUserC[] = "Proxy/user";
|
||||||
|
static const char proxyPassC[] = "Proxy/pass";
|
||||||
|
static const char proxyNeedsAuthC[] = "Proxy/needsAuth";
|
||||||
|
|
||||||
|
static const char useUploadLimitC[] = "BWLimit/useUploadLimit";
|
||||||
|
static const char useDownloadLimitC[] = "BWLimit/useDownloadLimit";
|
||||||
|
static const char uploadLimitC[] = "BWLimit/uploadLimit";
|
||||||
|
static const char downloadLimitC[] = "BWLimit/downloadLimit";
|
||||||
|
|
||||||
|
static const char seenVersionC[] = "Updater/seenVersion";
|
||||||
|
static const char maxLogLinesC[] = "Logging/maxLogLines";
|
||||||
|
|
||||||
QString MirallConfigFile::_oCVersion;
|
QString MirallConfigFile::_oCVersion;
|
||||||
QString MirallConfigFile::_confDir = QString::null;
|
QString MirallConfigFile::_confDir = QString::null;
|
||||||
bool MirallConfigFile::_askedUser = false;
|
bool MirallConfigFile::_askedUser = false;
|
||||||
|
QMap< QString, MirallConfigFile::SharedCreds > MirallConfigFile::credentialsPerConfig;
|
||||||
|
|
||||||
MirallConfigFile::MirallConfigFile( const QString& appendix )
|
MirallConfigFile::MirallConfigFile( const QString& appendix, bool useOldConfig )
|
||||||
:_customHandle(appendix)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (useOldConfig && !appendix.isEmpty()) {
|
||||||
|
QString oldConfigFile = configFile();
|
||||||
|
_customHandle = appendix;
|
||||||
|
QString newConfigFile = configFile();
|
||||||
|
QFile::copy(oldConfigFile, newConfigFile);
|
||||||
|
} else {
|
||||||
|
_customHandle = appendix;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
|
if (! credentialsPerConfig.contains(_customHandle)) {
|
||||||
|
QString con( _customHandle );
|
||||||
|
if( _customHandle.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
|
const QString config = configFile();
|
||||||
|
qDebug() << "Loading config: " << config;
|
||||||
|
|
||||||
|
|
||||||
|
QSettings settings(config, QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
settings.beginGroup( con );
|
||||||
|
|
||||||
|
QString type = settings.value( QLatin1String(authTypeC) ).toString();
|
||||||
|
|
||||||
|
qDebug() << "Getting credentials of type " << type << " for " << _customHandle;
|
||||||
|
|
||||||
|
credentialsPerConfig.insert(_customHandle, SharedCreds(CredentialsFactory::create (type)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MirallConfigFile::setConfDir(const QString &value)
|
void MirallConfigFile::setConfDir(const QString &value)
|
||||||
{
|
{
|
||||||
if( value.isEmpty() ) return;
|
QString dirPath = value;
|
||||||
|
if( dirPath.isEmpty() ) return;
|
||||||
|
|
||||||
QFileInfo fi(value);
|
QFileInfo fi(dirPath);
|
||||||
if( fi.exists() && fi.isDir() ) {
|
if ( !fi.exists() && !fi.isAbsolute() ) {
|
||||||
qDebug() << "** Using custom config dir " << value;
|
QDir::current().mkdir(dirPath);
|
||||||
_confDir=value;
|
QDir dir = QDir::current();
|
||||||
|
dir.cd(dirPath);
|
||||||
|
fi.setFile(dir.path());
|
||||||
}
|
}
|
||||||
|
if( fi.exists() && fi.isDir() ) {
|
||||||
|
dirPath = fi.absoluteFilePath();
|
||||||
|
qDebug() << "** Using custom config dir " << dirPath;
|
||||||
|
_confDir=dirPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MirallConfigFile::optionalDesktopNotifications() const
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setOptionalDesktopNotifications(bool show)
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
settings.setValue(QLatin1String(optionalDesktopNoficationsC), show);
|
||||||
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::seenVersion() const
|
QString MirallConfigFile::seenVersion() const
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup(QLatin1String("Updater"));
|
return settings.value(QLatin1String(seenVersionC)).toString();
|
||||||
return settings.value(QLatin1String("seenVersion")).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MirallConfigFile::setSeenVersion(const QString &version)
|
void MirallConfigFile::setSeenVersion(const QString &version)
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup(QLatin1String("Updater"));
|
settings.setValue(QLatin1String(seenVersionC), version);
|
||||||
settings.setValue(QLatin1String("seenVersion"), version);
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::saveGeometry(QWidget *w)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!w->objectName().isNull());
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
settings.beginGroup(w->objectName());
|
||||||
|
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
|
||||||
|
settings.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::restoreGeometry(QWidget *w)
|
||||||
|
{
|
||||||
|
w->restoreGeometry(getValue(geometryC, w->objectName()).toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::configPath() const
|
QString MirallConfigFile::configPath() const
|
||||||
{
|
{
|
||||||
QString dir = _confDir;
|
if( _confDir.isEmpty() ) {
|
||||||
if( _confDir.isEmpty() )
|
|
||||||
_confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
_confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||||
|
}
|
||||||
|
QString dir = _confDir;
|
||||||
|
|
||||||
if( !dir.endsWith(QLatin1Char('/')) ) dir.append(QLatin1Char('/'));
|
if( !dir.endsWith(QLatin1Char('/')) ) dir.append(QLatin1Char('/'));
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::excludeFile() const
|
QString MirallConfigFile::excludeFile(Scope scope) const
|
||||||
{
|
{
|
||||||
// prefer sync-exclude.lst, but if it does not exist, check for
|
// prefer sync-exclude.lst, but if it does not exist, check for
|
||||||
// exclude.lst for compatibility reasonsin the user writeable
|
// exclude.lst for compatibility reasons in the user writeable
|
||||||
// directories.
|
// directories.
|
||||||
const QString exclFile("sync-exclude.lst");
|
const QString exclFile("sync-exclude.lst");
|
||||||
|
|
||||||
QFileInfo fi;
|
QFileInfo fi;
|
||||||
fi.setFile( configPath(), exclFile );
|
|
||||||
|
|
||||||
if( ! fi.isReadable() ) {
|
if (scope != SystemScope) {
|
||||||
fi.setFile( configPath(), QLatin1String("exclude.lst") );
|
fi.setFile( configPath(), exclFile );
|
||||||
|
|
||||||
|
if( ! fi.isReadable() ) {
|
||||||
|
fi.setFile( configPath(), QLatin1String("exclude.lst") );
|
||||||
|
}
|
||||||
|
if( ! fi.isReadable() ) {
|
||||||
|
fi.setFile( configPath(), exclFile );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check alternative places...
|
if (scope != UserScope) {
|
||||||
if( ! fi.isReadable() ) {
|
// Check alternative places...
|
||||||
#ifdef Q_OS_WIN32
|
if( ! fi.isReadable() ) {
|
||||||
fi.setFile( QApplication::applicationDirPath(), exclFile );
|
#ifdef Q_OS_WIN
|
||||||
|
fi.setFile( QApplication::applicationDirPath(), exclFile );
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_UNIX
|
||||||
fi.setFile( QString("/etc/%1").arg(Theme::instance()->appName()), exclFile );
|
fi.setFile( QString("/etc/%1").arg(Theme::instance()->appName()), exclFile );
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
// exec path is inside the bundle
|
// exec path is inside the bundle
|
||||||
fi.setFile( QApplication::applicationDirPath(),
|
fi.setFile( QApplication::applicationDirPath(),
|
||||||
QLatin1String("../Resources/") + exclFile );
|
QLatin1String("../Resources/") + exclFile );
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
qDebug() << " ==> returning exclude file path: " << fi.absoluteFilePath();
|
||||||
if( fi.isReadable() ) {
|
return fi.absoluteFilePath();
|
||||||
qDebug() << " ==> returning exclude file path: " << fi.absoluteFilePath();
|
|
||||||
return fi.absoluteFilePath();
|
|
||||||
}
|
|
||||||
qDebug() << "EMPTY exclude file path!";
|
qDebug() << "EMPTY exclude file path!";
|
||||||
return QString::null;
|
return QString::null;
|
||||||
}
|
}
|
||||||
@@ -118,13 +213,13 @@ QString MirallConfigFile::configFile() const
|
|||||||
if( qApp->applicationName().isEmpty() ) {
|
if( qApp->applicationName().isEmpty() ) {
|
||||||
qApp->setApplicationName( Theme::instance()->appNameGUI() );
|
qApp->setApplicationName( Theme::instance()->appNameGUI() );
|
||||||
}
|
}
|
||||||
QString dir = configPath() + Theme::instance()->configFileName();
|
QString file = configPath() + Theme::instance()->configFileName();
|
||||||
if( !_customHandle.isEmpty() ) {
|
if( !_customHandle.isEmpty() ) {
|
||||||
dir.append( QLatin1Char('_'));
|
file.append( QLatin1Char('_'));
|
||||||
dir.append( _customHandle );
|
file.append( _customHandle );
|
||||||
qDebug() << " OO Custom config file in use: " << dir;
|
qDebug() << __PRETTY_FUNCTION__ << " OO Custom config file in use: " << file;
|
||||||
}
|
}
|
||||||
return dir;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MirallConfigFile::exists()
|
bool MirallConfigFile::exists()
|
||||||
@@ -143,122 +238,92 @@ bool MirallConfigFile::connectionExists( const QString& conn )
|
|||||||
QString con = conn;
|
QString con = conn;
|
||||||
if( conn.isEmpty() ) con = defaultConnection();
|
if( conn.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
return settings.contains( QString::fromLatin1("%1/url").arg( conn ) );
|
settings.beginGroup(conn);
|
||||||
|
return settings.contains( QLatin1String(urlC) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MirallConfigFile::writeOwncloudConfig( const QString& connection,
|
void MirallConfigFile::writeOwncloudConfig( const QString& connection,
|
||||||
const QString& url,
|
const QString& url,
|
||||||
const QString& user,
|
AbstractCredentials* credentials)
|
||||||
const QString& passwd )
|
|
||||||
{
|
{
|
||||||
const QString file = configFile();
|
const QString file = configFile();
|
||||||
bool skipPwd = false; // can be refactored - remove it.
|
qDebug() << "*** writing mirall config to " << file;
|
||||||
qDebug() << "*** writing mirall config to " << file << " Skippwd: " << skipPwd;
|
|
||||||
|
|
||||||
QSettings settings( file, QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
settings.beginGroup( connection );
|
settings.beginGroup( connection );
|
||||||
settings.setValue( QLatin1String("url"), url );
|
settings.setValue( QLatin1String(urlC), url );
|
||||||
settings.setValue( QLatin1String("user"), user );
|
settings.setValue(QLatin1String(authTypeC), credentials->authType());
|
||||||
|
credentialsPerConfig.insert(_customHandle, SharedCreds(credentials));
|
||||||
|
|
||||||
#ifdef WITH_QTKEYCHAIN
|
|
||||||
// Password is stored to QtKeyChain now by default in CredentialStore
|
|
||||||
// The CredentialStore calls clearPasswordFromConfig after the creds
|
|
||||||
// were successfully wiritten to delete the passwd entry from config.
|
|
||||||
qDebug() << "Going to delete the password from settings file.";
|
|
||||||
#else
|
|
||||||
if( !skipPwd )
|
|
||||||
writePassword( passwd );
|
|
||||||
#endif
|
|
||||||
if( !skipPwd )
|
|
||||||
writePassword( passwd );
|
|
||||||
else
|
|
||||||
clearPasswordFromConfig(); // wipe the password.
|
|
||||||
|
|
||||||
settings.setValue( QLatin1String("nostoredpassword"), QVariant(skipPwd) );
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
// check the perms, only read-write for the owner.
|
// check the perms, only read-write for the owner.
|
||||||
QFile::setPermissions( file, QFile::ReadOwner|QFile::WriteOwner );
|
QFile::setPermissions( file, QFile::ReadOwner|QFile::WriteOwner );
|
||||||
|
|
||||||
// Store credentials temporar until the config is finalized.
|
// Store credentials temporar until the config is finalized.
|
||||||
ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle );
|
//ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called after the password was successfully stored into the
|
void MirallConfigFile::storeData(const QString& group, const QString& key, const QVariant& value)
|
||||||
// QKeyChain in CredentialStore.
|
|
||||||
void MirallConfigFile::clearPasswordFromConfig( const QString& connection )
|
|
||||||
{
|
{
|
||||||
const QString file = configFile();
|
const QString con(group.isEmpty() ? defaultConnection() : group);
|
||||||
QString con( defaultConnection() );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
if( !connection.isEmpty() )
|
settings.setIniCodec("UTF-8");
|
||||||
con = connection;
|
|
||||||
|
|
||||||
QSettings settings( file, QSettings::IniFormat);
|
settings.beginGroup(con);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setValue(key, value);
|
||||||
settings.beginGroup( con );
|
|
||||||
settings.remove(QLatin1String("passwd"));
|
|
||||||
settings.remove(QLatin1String("password"));
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MirallConfigFile::writePassword( const QString& passwd, const QString& connection )
|
QVariant MirallConfigFile::retrieveData(const QString& group, const QString& key) const
|
||||||
{
|
{
|
||||||
const QString file = configFile();
|
const QString con(group.isEmpty() ? defaultConnection() : group);
|
||||||
QString pwd( passwd );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
QString con( defaultConnection() );
|
settings.setIniCodec("UTF-8");
|
||||||
if( !connection.isEmpty() )
|
|
||||||
con = connection;
|
|
||||||
|
|
||||||
QSettings settings( file, QSettings::IniFormat);
|
settings.beginGroup(con);
|
||||||
settings.setIniCodec( "UTF-8" );
|
return settings.value(key);
|
||||||
|
|
||||||
// store password into settings file.
|
|
||||||
settings.beginGroup( con );
|
|
||||||
QByteArray pwdba = pwd.toUtf8();
|
|
||||||
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
|
|
||||||
settings.sync();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the url, called from redirect handling.
|
void MirallConfigFile::removeData(const QString& group, const QString& key)
|
||||||
void MirallConfigFile::setOwnCloudUrl( const QString& connection, const QString & url )
|
|
||||||
{
|
{
|
||||||
const QString file = configFile();
|
const QString con(group.isEmpty() ? defaultConnection() : group);
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
QSettings settings( file, QSettings::IniFormat);
|
settings.beginGroup(con);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.remove(key);
|
||||||
settings.beginGroup( connection );
|
}
|
||||||
settings.setValue( QLatin1String("url"), url );
|
|
||||||
|
|
||||||
settings.sync();
|
bool MirallConfigFile::dataExists(const QString& group, const QString& key) const
|
||||||
|
{
|
||||||
|
const QString con(group.isEmpty() ? defaultConnection() : group);
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
|
settings.beginGroup(con);
|
||||||
|
return settings.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray MirallConfigFile::caCerts( )
|
QByteArray MirallConfigFile::caCerts( )
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
|
return settings.value( QLatin1String(caCertsKeyC) ).toByteArray();
|
||||||
QByteArray certs = settings.value( CA_CERTS_KEY ).toByteArray();
|
|
||||||
|
|
||||||
return certs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MirallConfigFile::setCaCerts( const QByteArray & certs )
|
void MirallConfigFile::setCaCerts( const QByteArray & certs )
|
||||||
{
|
{
|
||||||
const QString file = configFile();
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
QSettings settings( file, QSettings::IniFormat);
|
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec( "UTF-8" );
|
||||||
settings.setValue( CA_CERTS_KEY, certs );
|
settings.setValue( QLatin1String(caCertsKeyC), certs );
|
||||||
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +336,8 @@ void MirallConfigFile::removeConnection( const QString& connection )
|
|||||||
qDebug() << " removing the config file for connection " << con;
|
qDebug() << " removing the config file for connection " << con;
|
||||||
|
|
||||||
// Currently its just removing the entire config file
|
// Currently its just removing the entire config file
|
||||||
QSettings settings( configFile(), QSettings::IniFormat);
|
// TODO: Eh? Shouldn't it try to load a file under configFile() and set it to INI?
|
||||||
|
QSettings settings;
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec( "UTF-8" );
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
settings.remove(QString::null); // removes all content from the group
|
settings.remove(QString::null); // removes all content from the group
|
||||||
@@ -282,41 +348,22 @@ void MirallConfigFile::removeConnection( const QString& connection )
|
|||||||
* returns the configured owncloud url if its already configured, otherwise an empty
|
* returns the configured owncloud url if its already configured, otherwise an empty
|
||||||
* string.
|
* string.
|
||||||
* The returned url always has a trailing hash.
|
* The returned url always has a trailing hash.
|
||||||
* If webdav is true, the webdav-server url is returned.
|
|
||||||
*/
|
*/
|
||||||
QString MirallConfigFile::ownCloudUrl( const QString& connection, bool webdav ) const
|
QString MirallConfigFile::ownCloudUrl( const QString& connection) const
|
||||||
{
|
{
|
||||||
QString con( connection );
|
QString con( connection );
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
if( connection.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
QString url = settings.value( QLatin1String("url") ).toString();
|
QString url = settings.value( QLatin1String(urlC) ).toString();
|
||||||
if( ! url.isEmpty() ) {
|
if( ! url.isEmpty() ) {
|
||||||
if( ! url.endsWith(QLatin1Char('/'))) url.append(QLatin1String("/"));
|
if( ! url.endsWith(QLatin1Char('/'))) url.append(QLatin1String("/"));
|
||||||
if( webdav ) url.append( QLatin1String("remote.php/webdav/") );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Returning configured owncloud url: " << url;
|
return url;
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MirallConfigFile::ownCloudUser( const QString& connection ) const
|
|
||||||
{
|
|
||||||
QString con( connection );
|
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
|
||||||
settings.setIniCodec( "UTF-8" );
|
|
||||||
settings.beginGroup( con );
|
|
||||||
|
|
||||||
QString user = settings.value( QLatin1String("user") ).toString();
|
|
||||||
// qDebug() << "Returning configured owncloud user: " << user;
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MirallConfigFile::remotePollInterval( const QString& connection ) const
|
int MirallConfigFile::remotePollInterval( const QString& connection ) const
|
||||||
@@ -324,11 +371,11 @@ int MirallConfigFile::remotePollInterval( const QString& connection ) const
|
|||||||
QString con( connection );
|
QString con( connection );
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
if( connection.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
int remoteInterval = settings.value( QLatin1String("remotePollInterval"), DEFAULT_REMOTE_POLL_INTERVAL ).toInt();
|
int remoteInterval = settings.value( QLatin1String(remotePollIntervalC), DEFAULT_REMOTE_POLL_INTERVAL ).toInt();
|
||||||
if( remoteInterval < 5000) {
|
if( remoteInterval < 5000) {
|
||||||
qDebug() << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL;
|
qDebug() << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL;
|
||||||
remoteInterval = DEFAULT_REMOTE_POLL_INTERVAL;
|
remoteInterval = DEFAULT_REMOTE_POLL_INTERVAL;
|
||||||
@@ -345,52 +392,29 @@ void MirallConfigFile::setRemotePollInterval(int interval, const QString &connec
|
|||||||
qDebug() << "Remote Poll interval of " << interval << " is below fife seconds.";
|
qDebug() << "Remote Poll interval of " << interval << " is below fife seconds.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
settings.setValue("remotePollInterval", interval );
|
settings.setValue(QLatin1String(remotePollIntervalC), interval );
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MirallConfigFile::passwordStorageAllowed( const QString& connection )
|
quint64 MirallConfigFile::forceSyncInterval(const QString& connection) const
|
||||||
{
|
{
|
||||||
|
uint pollInterval = remotePollInterval(connection);
|
||||||
|
|
||||||
QString con( connection );
|
QString con( connection );
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
if( connection.isEmpty() ) con = defaultConnection();
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.setIniCodec( "UTF-8" );
|
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
bool skipPwd = settings.value( QLatin1String("nostoredpassword"), false ).toBool();
|
quint64 interval = settings.value( QLatin1String(forceSyncIntervalC), 10 * pollInterval ).toULongLong();
|
||||||
return !skipPwd;
|
if( interval < pollInterval) {
|
||||||
}
|
qDebug() << "Force sync interval is less than the remote poll inteval, reverting to" << pollInterval;
|
||||||
|
interval = pollInterval;
|
||||||
QString MirallConfigFile::ownCloudPasswd( const QString& connection ) const
|
|
||||||
{
|
|
||||||
QString con( connection );
|
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
|
||||||
settings.setIniCodec( "UTF-8" );
|
|
||||||
settings.beginGroup( con );
|
|
||||||
|
|
||||||
QByteArray pwdba = settings.value(QLatin1String("passwd")).toByteArray();
|
|
||||||
if( !pwdba.isEmpty() ) {
|
|
||||||
return QString::fromUtf8( QByteArray::fromBase64(pwdba) );
|
|
||||||
}
|
}
|
||||||
|
return interval;
|
||||||
// check the password entry, cleartext from before
|
|
||||||
// read it and convert to base64, delete the cleartext entry.
|
|
||||||
QString p = settings.value(QLatin1String("password")).toString();
|
|
||||||
|
|
||||||
if( ! p.isEmpty() ) {
|
|
||||||
// its there, save base64-encoded and delete.
|
|
||||||
pwdba = p.toUtf8();
|
|
||||||
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
|
|
||||||
settings.remove( QLatin1String("password") );
|
|
||||||
settings.sync();
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::ownCloudVersion() const
|
QString MirallConfigFile::ownCloudVersion() const
|
||||||
@@ -410,11 +434,11 @@ bool MirallConfigFile::ownCloudSkipUpdateCheck( const QString& connection ) cons
|
|||||||
QString con( connection );
|
QString con( connection );
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
if( connection.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
bool skipIt = settings.value( QLatin1String("skipUpdateCheck"), false ).toBool();
|
bool skipIt = settings.value( QLatin1String(skipUpdateCheckC), false ).toBool();
|
||||||
|
|
||||||
return skipIt;
|
return skipIt;
|
||||||
}
|
}
|
||||||
@@ -424,31 +448,27 @@ void MirallConfigFile::setOwnCloudSkipUpdateCheck( bool skip, const QString& con
|
|||||||
QString con( connection );
|
QString con( connection );
|
||||||
if( connection.isEmpty() ) con = defaultConnection();
|
if( connection.isEmpty() ) con = defaultConnection();
|
||||||
|
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
settings.setValue( QLatin1String("skipUpdateCheck"), QVariant(skip) );
|
settings.setValue( QLatin1String(skipUpdateCheckC), QVariant(skip) );
|
||||||
settings.sync();
|
settings.sync();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MirallConfigFile::maxLogLines() const
|
int MirallConfigFile::maxLogLines() const
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup(QLatin1String("Logging"));
|
return settings.value( QLatin1String(maxLogLinesC), DEFAULT_MAX_LOG_LINES ).toInt();
|
||||||
int logLines = settings.value( QLatin1String("maxLogLines"), 20000 ).toInt();
|
|
||||||
return logLines;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MirallConfigFile::setMaxLogLines( int lines )
|
void MirallConfigFile::setMaxLogLines( int lines )
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
|
settings.setValue(QLatin1String(maxLogLinesC), lines);
|
||||||
settings.beginGroup(QLatin1String("Logging"));
|
|
||||||
settings.setValue(QLatin1String("maxLogLines"), lines);
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,6 +495,8 @@ void MirallConfigFile::acceptCustomConfig()
|
|||||||
|
|
||||||
QString srcConfig = configFile(); // this considers the custom handle
|
QString srcConfig = configFile(); // this considers the custom handle
|
||||||
|
|
||||||
|
credentialsPerConfig.insert(QString(), credentialsPerConfig[_customHandle]);
|
||||||
|
credentialsPerConfig.remove(_customHandle);
|
||||||
_customHandle.clear();
|
_customHandle.clear();
|
||||||
QString targetConfig = configFile();
|
QString targetConfig = configFile();
|
||||||
QString targetBak = targetConfig + QLatin1String(".bak");
|
QString targetBak = targetConfig + QLatin1String(".bak");
|
||||||
@@ -496,18 +518,7 @@ void MirallConfigFile::acceptCustomConfig()
|
|||||||
}
|
}
|
||||||
QFile::remove( targetBak );
|
QFile::remove( targetBak );
|
||||||
|
|
||||||
// inform the credential store about the password change.
|
credentialsPerConfig[QString()]->persistForUrl(ownCloudUrl());
|
||||||
QString url = ownCloudUrl();
|
|
||||||
QString user = ownCloudUser();
|
|
||||||
QString pwd = ownCloudPasswd();
|
|
||||||
bool allow = passwordStorageAllowed();
|
|
||||||
|
|
||||||
if( pwd.isEmpty() ) {
|
|
||||||
qDebug() << "Password is empty, skipping to write cred store.";
|
|
||||||
} else {
|
|
||||||
CredentialStore::instance()->setCredentials(url, user, pwd, allow);
|
|
||||||
CredentialStore::instance()->saveCredentials();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MirallConfigFile::setProxyType(int proxyType,
|
void MirallConfigFile::setProxyType(int proxyType,
|
||||||
@@ -516,61 +527,129 @@ void MirallConfigFile::setProxyType(int proxyType,
|
|||||||
const QString& user,
|
const QString& user,
|
||||||
const QString& pass)
|
const QString& pass)
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup(QLatin1String("proxy"));
|
|
||||||
|
|
||||||
settings.setValue(QLatin1String("type"), proxyType);
|
settings.setValue(QLatin1String(proxyTypeC), proxyType);
|
||||||
|
|
||||||
if (proxyType == QNetworkProxy::HttpProxy ||
|
if (proxyType == QNetworkProxy::HttpProxy ||
|
||||||
proxyType == QNetworkProxy::Socks5Proxy) {
|
proxyType == QNetworkProxy::Socks5Proxy) {
|
||||||
settings.setValue(QLatin1String("host"), host);
|
settings.setValue(QLatin1String(proxyHostC), host);
|
||||||
settings.setValue(QLatin1String("port"), port);
|
settings.setValue(QLatin1String(proxyPortC), port);
|
||||||
settings.setValue(QLatin1String("needsAuth"), needsAuth);
|
settings.setValue(QLatin1String(proxyNeedsAuthC), needsAuth);
|
||||||
settings.setValue(QLatin1String("user"), user);
|
settings.setValue(QLatin1String(proxyUserC), user);
|
||||||
settings.setValue(QLatin1String("pass"), pass.toUtf8().toBase64());
|
settings.setValue(QLatin1String(proxyPassC), pass.toUtf8().toBase64());
|
||||||
}
|
}
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant MirallConfigFile::getValue(const QString& param, const QString& group) const
|
QVariant MirallConfigFile::getValue(const QString& param, const QString& group,
|
||||||
|
const QVariant& defaultValue) const
|
||||||
{
|
{
|
||||||
QSettings settings( configFile(), QSettings::IniFormat );
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec("UTF-8");
|
||||||
settings.beginGroup(group);
|
if (!group.isEmpty())
|
||||||
|
settings.beginGroup(group);
|
||||||
|
|
||||||
return settings.value(param);
|
return settings.value(param, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setValue(const QString& key, const QVariant &value)
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
|
||||||
|
settings.setValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MirallConfigFile::proxyType() const
|
int MirallConfigFile::proxyType() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("type"), QLatin1String("proxy")).toInt();
|
return getValue(QLatin1String(proxyTypeC)).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::proxyHostName() const
|
QString MirallConfigFile::proxyHostName() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("host"), QLatin1String("proxy")).toString();
|
return getValue(QLatin1String(proxyHostC)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MirallConfigFile::proxyPort() const
|
int MirallConfigFile::proxyPort() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("port"), QLatin1String("proxy")).toInt();
|
return getValue(QLatin1String(proxyPortC)).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MirallConfigFile::proxyNeedsAuth() const
|
bool MirallConfigFile::proxyNeedsAuth() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toBool();
|
return getValue(QLatin1String(proxyNeedsAuthC)).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::proxyUser() const
|
QString MirallConfigFile::proxyUser() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("user"), QLatin1String("proxy")).toString();
|
return getValue(QLatin1String(proxyUserC)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::proxyPassword() const
|
QString MirallConfigFile::proxyPassword() const
|
||||||
{
|
{
|
||||||
QByteArray pass = getValue(QLatin1String("pass"), QLatin1String("proxy")).toByteArray();
|
QByteArray pass = getValue(proxyPassC).toByteArray();
|
||||||
return QString::fromUtf8(QByteArray::fromBase64(pass));
|
return QString::fromUtf8(QByteArray::fromBase64(pass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MirallConfigFile::useUploadLimit() const
|
||||||
|
{
|
||||||
|
return getValue(useUploadLimitC, QString::null, -1).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MirallConfigFile::useDownloadLimit() const
|
||||||
|
{
|
||||||
|
return getValue(useDownloadLimitC, QString::null, false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setUseUploadLimit(int val)
|
||||||
|
{
|
||||||
|
setValue(useUploadLimitC, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setUseDownloadLimit(bool enable)
|
||||||
|
{
|
||||||
|
setValue(useDownloadLimitC, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MirallConfigFile::uploadLimit() const
|
||||||
|
{
|
||||||
|
return getValue(uploadLimitC, QString::null, 10).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MirallConfigFile::downloadLimit() const
|
||||||
|
{
|
||||||
|
return getValue(downloadLimitC, QString::null, 80).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setUploadLimit(int kbytes)
|
||||||
|
{
|
||||||
|
setValue(uploadLimitC, kbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setDownloadLimit(int kbytes)
|
||||||
|
{
|
||||||
|
setValue(downloadLimitC, kbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MirallConfigFile::monoIcons() const
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
return settings.value(QLatin1String(monoIconsC), false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MirallConfigFile::setMonoIcons(bool useMonoIcons)
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
settings.setIniCodec("UTF-8");
|
||||||
|
settings.setValue(QLatin1String(monoIconsC), useMonoIcons);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractCredentials* MirallConfigFile::getCredentials() const
|
||||||
|
{
|
||||||
|
return credentialsPerConfig[_customHandle].data();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,33 +15,26 @@
|
|||||||
#ifndef MIRALLCONFIGFILE_H
|
#ifndef MIRALLCONFIGFILE_H
|
||||||
#define MIRALLCONFIGFILE_H
|
#define MIRALLCONFIGFILE_H
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
class QVariant;
|
class QWidget;
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
|
class AbstractCredentials;
|
||||||
|
|
||||||
class MirallConfigFile
|
class MirallConfigFile
|
||||||
{
|
{
|
||||||
/* let only CredentialStore read the password from the file. All other classes
|
|
||||||
* should work with CredentialStore to get the credentials. */
|
|
||||||
friend class CredentialStore;
|
|
||||||
friend class ConnectionValidator;
|
|
||||||
public:
|
public:
|
||||||
MirallConfigFile( const QString& appendix = QString() );
|
MirallConfigFile( const QString& appendix = QString(), bool useOldConfig = false );
|
||||||
|
|
||||||
// enum customMediaType {
|
enum Scope { UserScope, SystemScope };
|
||||||
// oCSetupTop, // ownCloud connect page
|
|
||||||
// oCSetupSide,
|
|
||||||
// oCSetupBottom,
|
|
||||||
// oCSetupFixUrl,
|
|
||||||
// oCSetupResultTop // ownCloud connect result page
|
|
||||||
// };
|
|
||||||
|
|
||||||
QString configPath() const;
|
QString configPath() const;
|
||||||
QString configFile() const;
|
QString configFile() const;
|
||||||
QString excludeFile() const;
|
QString excludeFile(Scope scope) const;
|
||||||
|
|
||||||
bool exists();
|
bool exists();
|
||||||
|
|
||||||
@@ -50,15 +43,13 @@ public:
|
|||||||
|
|
||||||
void writeOwncloudConfig( const QString& connection,
|
void writeOwncloudConfig( const QString& connection,
|
||||||
const QString& url,
|
const QString& url,
|
||||||
const QString& user,
|
AbstractCredentials* credentials);
|
||||||
const QString& passwd );
|
|
||||||
|
AbstractCredentials* getCredentials() const;
|
||||||
|
|
||||||
void removeConnection( const QString& connection = QString() );
|
void removeConnection( const QString& connection = QString() );
|
||||||
|
|
||||||
QString ownCloudUser( const QString& connection = QString() ) const;
|
QString ownCloudUrl( const QString& connection = QString() ) const;
|
||||||
QString ownCloudUrl( const QString& connection = QString(), bool webdav = false ) const;
|
|
||||||
|
|
||||||
void setOwnCloudUrl(const QString &connection, const QString& );
|
|
||||||
|
|
||||||
// the certs do not depend on a connection.
|
// the certs do not depend on a connection.
|
||||||
QByteArray caCerts();
|
QByteArray caCerts();
|
||||||
@@ -81,11 +72,17 @@ public:
|
|||||||
/* Set poll interval. Value in microseconds has to be larger than 5000 */
|
/* Set poll interval. Value in microseconds has to be larger than 5000 */
|
||||||
void setRemotePollInterval(int interval, const QString& connection = QString() );
|
void setRemotePollInterval(int interval, const QString& connection = QString() );
|
||||||
|
|
||||||
|
/* Force sync interval, in milliseconds */
|
||||||
|
quint64 forceSyncInterval(const QString &connection = QString()) const;
|
||||||
|
|
||||||
// Custom Config: accept the custom config to become the main one.
|
// Custom Config: accept the custom config to become the main one.
|
||||||
void acceptCustomConfig();
|
void acceptCustomConfig();
|
||||||
// Custom Config: remove the custom config file.
|
// Custom Config: remove the custom config file.
|
||||||
void cleanupCustomConfig();
|
void cleanupCustomConfig();
|
||||||
|
|
||||||
|
bool monoIcons() const;
|
||||||
|
void setMonoIcons(bool);
|
||||||
|
|
||||||
// proxy settings
|
// proxy settings
|
||||||
void setProxyType(int proxyType,
|
void setProxyType(int proxyType,
|
||||||
const QString& host = QString(),
|
const QString& host = QString(),
|
||||||
@@ -100,26 +97,47 @@ public:
|
|||||||
QString proxyUser() const;
|
QString proxyUser() const;
|
||||||
QString proxyPassword() const;
|
QString proxyPassword() const;
|
||||||
|
|
||||||
|
/** 0: no limit, 1: manual, >0: automatic */
|
||||||
|
int useUploadLimit() const;
|
||||||
|
bool useDownloadLimit() const;
|
||||||
|
void setUseUploadLimit(int);
|
||||||
|
void setUseDownloadLimit(bool);
|
||||||
|
/** in kbyte/s */
|
||||||
|
int uploadLimit() const;
|
||||||
|
int downloadLimit() const;
|
||||||
|
void setUploadLimit(int kbytes);
|
||||||
|
void setDownloadLimit(int kbytes);
|
||||||
|
|
||||||
static void setConfDir(const QString &value);
|
static void setConfDir(const QString &value);
|
||||||
|
|
||||||
|
bool optionalDesktopNotifications() const;
|
||||||
|
void setOptionalDesktopNotifications(bool show);
|
||||||
|
|
||||||
QString seenVersion() const;
|
QString seenVersion() const;
|
||||||
void setSeenVersion(const QString &version);
|
void setSeenVersion(const QString &version);
|
||||||
|
|
||||||
|
void saveGeometry(QWidget *w);
|
||||||
|
void restoreGeometry(QWidget *w);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// these classes can only be access from CredentialStore as a friend class.
|
void storeData(const QString& group, const QString& key, const QVariant& value);
|
||||||
QString ownCloudPasswd( const QString& connection = QString() ) const;
|
QVariant retrieveData(const QString& group, const QString& key) const;
|
||||||
void clearPasswordFromConfig( const QString& connect = QString() );
|
void removeData(const QString& group, const QString& key);
|
||||||
bool writePassword( const QString& passwd, const QString& connection = QString() );
|
bool dataExists(const QString& group, const QString& key) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariant getValue(const QString& param, const QString& group) const;
|
QVariant getValue(const QString& param, const QString& group = QString::null,
|
||||||
|
const QVariant& defaultValue = QVariant()) const;
|
||||||
|
void setValue(const QString& key, const QVariant &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef QSharedPointer< AbstractCredentials > SharedCreds;
|
||||||
|
|
||||||
static bool _askedUser;
|
static bool _askedUser;
|
||||||
static QString _oCVersion;
|
static QString _oCVersion;
|
||||||
static QString _confDir;
|
static QString _confDir;
|
||||||
|
static QMap< QString, SharedCreds > credentialsPerConfig;
|
||||||
QString _customHandle;
|
QString _customHandle;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
161
src/mirall/networksettings.cpp
Normal file
161
src/mirall/networksettings.cpp
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "networksettings.h"
|
||||||
|
#include "ui_networksettings.h"
|
||||||
|
|
||||||
|
#include "mirall/theme.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
#include "mirall/application.h"
|
||||||
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/mirallconfigfile.h"
|
||||||
|
|
||||||
|
#include <QNetworkProxy>
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
NetworkSettings::NetworkSettings(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
_ui(new Ui::NetworkSettings)
|
||||||
|
{
|
||||||
|
_ui->setupUi(this);
|
||||||
|
|
||||||
|
_ui->hostLineEdit->setPlaceholderText(tr("Hostname of proxy server"));
|
||||||
|
_ui->userLineEdit->setPlaceholderText(tr("Username for proxy server"));
|
||||||
|
_ui->passwordLineEdit->setPlaceholderText(tr("Password for proxy server"));
|
||||||
|
|
||||||
|
_ui->typeComboBox->addItem(tr("HTTP(S) proxy"), QNetworkProxy::HttpProxy);
|
||||||
|
_ui->typeComboBox->addItem(tr("SOCKS5 proxy"), QNetworkProxy::Socks5Proxy);
|
||||||
|
|
||||||
|
_ui->authRequiredcheckBox->setEnabled(true);
|
||||||
|
|
||||||
|
connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)),
|
||||||
|
_ui->manualSettings, SLOT(setEnabled(bool)));
|
||||||
|
connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)),
|
||||||
|
_ui->typeComboBox, SLOT(setEnabled(bool)));
|
||||||
|
connect(_ui->authRequiredcheckBox, SIGNAL(toggled(bool)),
|
||||||
|
_ui->authWidgets, SLOT(setEnabled(bool)));
|
||||||
|
|
||||||
|
loadProxySettings();
|
||||||
|
loadBWLimitSettings();
|
||||||
|
|
||||||
|
// proxy
|
||||||
|
connect(_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(saveProxySettings()));
|
||||||
|
connect(_ui->proxyButtonGroup, SIGNAL(buttonClicked(int)), SLOT(saveProxySettings()));
|
||||||
|
connect(_ui->hostLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
|
||||||
|
connect(_ui->userLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
|
||||||
|
connect(_ui->passwordLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
|
||||||
|
connect(_ui->portSpinBox, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
|
||||||
|
|
||||||
|
connect(_ui->uploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->noUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->autoUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->downloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->noDownloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->downloadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
|
||||||
|
connect(_ui->uploadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkSettings::~NetworkSettings()
|
||||||
|
{
|
||||||
|
delete _ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::loadProxySettings()
|
||||||
|
{
|
||||||
|
// load current proxy settings
|
||||||
|
Mirall::MirallConfigFile cfgFile;
|
||||||
|
int type = cfgFile.proxyType();
|
||||||
|
switch (type) {
|
||||||
|
case QNetworkProxy::NoProxy:
|
||||||
|
_ui->noProxyRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
|
case QNetworkProxy::DefaultProxy:
|
||||||
|
_ui->systemProxyRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
|
case QNetworkProxy::Socks5Proxy:
|
||||||
|
case QNetworkProxy::HttpProxy:
|
||||||
|
_ui->typeComboBox->setCurrentIndex(_ui->typeComboBox->findData(type));
|
||||||
|
_ui->manualProxyRadioButton->setChecked(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ui->hostLineEdit->setText(cfgFile.proxyHostName());
|
||||||
|
int port = cfgFile.proxyPort();
|
||||||
|
if (port == 0)
|
||||||
|
port = 8080;
|
||||||
|
_ui->portSpinBox->setValue(port);
|
||||||
|
if (!cfgFile.proxyUser().isEmpty())
|
||||||
|
{
|
||||||
|
_ui->authRequiredcheckBox->setChecked(true);
|
||||||
|
_ui->userLineEdit->setText(cfgFile.proxyUser());
|
||||||
|
_ui->passwordLineEdit->setText(cfgFile.proxyPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::loadBWLimitSettings()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
_ui->downloadLimitRadioButton->setChecked(cfgFile.useDownloadLimit());
|
||||||
|
int uploadLimit = cfgFile.useUploadLimit();
|
||||||
|
if ( uploadLimit >= 1 ) {
|
||||||
|
_ui->uploadLimitRadioButton->setChecked(true);
|
||||||
|
} else if (uploadLimit == 0){
|
||||||
|
_ui->noDownloadLimitRadioButton->setChecked(true);
|
||||||
|
} else {
|
||||||
|
_ui->autoUploadLimitRadioButton->setChecked(true);
|
||||||
|
}
|
||||||
|
_ui->downloadSpinBox->setValue(cfgFile.downloadLimit());
|
||||||
|
_ui->uploadSpinBox->setValue(cfgFile.uploadLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::saveProxySettings()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
|
||||||
|
if (_ui->noProxyRadioButton->isChecked()){
|
||||||
|
cfgFile.setProxyType(QNetworkProxy::NoProxy);
|
||||||
|
} else if (_ui->systemProxyRadioButton->isChecked()){
|
||||||
|
cfgFile.setProxyType(QNetworkProxy::DefaultProxy);
|
||||||
|
} else if (_ui->manualProxyRadioButton->isChecked()) {
|
||||||
|
int type = _ui->typeComboBox->itemData(_ui->typeComboBox->currentIndex()).toInt();
|
||||||
|
bool needsAuth = _ui->authRequiredcheckBox->isChecked();
|
||||||
|
QString user = _ui->userLineEdit->text();
|
||||||
|
QString pass = _ui->passwordLineEdit->text();
|
||||||
|
cfgFile.setProxyType(type, _ui->hostLineEdit->text(),
|
||||||
|
_ui->portSpinBox->value(), needsAuth, user, pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit proxySettingsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSettings::saveBWLimitSettings()
|
||||||
|
{
|
||||||
|
MirallConfigFile cfgFile;
|
||||||
|
cfgFile.setUseDownloadLimit(_ui->downloadLimitRadioButton->isChecked());
|
||||||
|
|
||||||
|
if (_ui->uploadLimitRadioButton->isChecked()) {
|
||||||
|
cfgFile.setUseUploadLimit(1);
|
||||||
|
} else if (_ui->noUploadLimitRadioButton->isChecked()) {
|
||||||
|
cfgFile.setUseUploadLimit(0);
|
||||||
|
} else if (_ui->autoUploadLimitRadioButton->isChecked()) {
|
||||||
|
cfgFile.setUseUploadLimit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgFile.setDownloadLimit(_ui->downloadSpinBox->value());
|
||||||
|
cfgFile.setUploadLimit(_ui->uploadSpinBox->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
50
src/mirall/networksettings.h
Normal file
50
src/mirall/networksettings.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_NETWORKSETTINGS_H
|
||||||
|
#define MIRALL_NETWORKSETTINGS_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Mirall {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class NetworkSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NetworkSettings : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NetworkSettings(QWidget *parent = 0);
|
||||||
|
~NetworkSettings();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void proxySettingsChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void saveProxySettings();
|
||||||
|
void saveBWLimitSettings();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadProxySettings();
|
||||||
|
void loadBWLimitSettings();
|
||||||
|
|
||||||
|
Ui::NetworkSettings *_ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Mirall
|
||||||
|
#endif // MIRALL_NETWORKSETTINGS_H
|
||||||
371
src/mirall/networksettings.ui
Normal file
371
src/mirall/networksettings.ui
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Mirall::NetworkSettings</class>
|
||||||
|
<widget class="QWidget" name="Mirall::NetworkSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>518</width>
|
||||||
|
<height>384</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="proxyGroupBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Proxy Settings</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QRadioButton" name="noProxyRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>No Proxy</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">proxyButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QRadioButton" name="systemProxyRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use system proxy</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">proxyButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QRadioButton" name="manualProxyRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Specify proxy manually as</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">proxyButtonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="typeComboBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QWidget" name="manualSettings" native="true">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="hostLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Host</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="hostLineEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="portSpinBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>65535</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>8080</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="authRequiredcheckBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Proxy server requires authentication</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="authWidgets" native="true">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="userLineEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="passwordLineEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Download Bandwidth</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QRadioButton" name="downloadLimitRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Limit to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="downloadSpinBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>9999</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>80</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>KBytes/s</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>147</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QRadioButton" name="noDownloadLimitRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>No Limit</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Upload Bandwidth</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QRadioButton" name="noUploadLimitRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>No Limit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QRadioButton" name="autoUploadLimitRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Limit automatically</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QRadioButton" name="uploadLimitRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Limit to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="uploadSpinBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>9999</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>KBytes/s</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<zorder>autoUploadLimitRadioButton</zorder>
|
||||||
|
<zorder>uploadLimitRadioButton</zorder>
|
||||||
|
<zorder>noUploadLimitRadioButton</zorder>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>downloadLimitRadioButton</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>downloadSpinBox</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>73</x>
|
||||||
|
<y>69</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>131</x>
|
||||||
|
<y>78</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>uploadLimitRadioButton</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>uploadSpinBox</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>322</x>
|
||||||
|
<y>101</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>411</x>
|
||||||
|
<y>106</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<buttongroups>
|
||||||
|
<buttongroup name="proxyButtonGroup"/>
|
||||||
|
</buttongroups>
|
||||||
|
</ui>
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>OwncloudCredentialsPage</class>
|
|
||||||
<widget class="QWidget" name="OwncloudCredentialsPage">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>576</width>
|
|
||||||
<height>302</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>14</pointsize>
|
|
||||||
<weight>50</weight>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>ownCloud Credentials</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_17">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Provide ownCloud Credentials</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
|
||||||
p, li { white-space: pre-wrap; }
|
|
||||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt; color:#585858;">Please enter the username and password for your ownCloud Instance. </span></p>
|
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt; color:#585858;"><br /></p>
|
|
||||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt; color:#585858;">If you do not wish to store the credentials on your local machine, check the box. ownCloud will prompt you for your password every time the client starts.</span></p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="textFormat">
|
|
||||||
<enum>Qt::AutoText</enum>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<layout class="QFormLayout" name="formLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>ownCloud-User:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLineEdit" name="OCUserEdit">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Password:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="OCPasswdEdit">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="echoMode">
|
|
||||||
<enum>QLineEdit::Password</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QCheckBox" name="cbPwdNoLocalStore">
|
|
||||||
<property name="text">
|
|
||||||
<string>Do not store password on local machine.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>568</width>
|
|
||||||
<height>158</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@@ -1,532 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
|
||||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.org>
|
|
||||||
*
|
|
||||||
* 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 "mirall/owncloudfolder.h"
|
|
||||||
#include "mirall/mirallconfigfile.h"
|
|
||||||
#include "mirall/owncloudinfo.h"
|
|
||||||
#include "mirall/credentialstore.h"
|
|
||||||
#include "mirall/logger.h"
|
|
||||||
#include "mirall/utility.h"
|
|
||||||
|
|
||||||
#include <csync.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QNetworkProxy>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkProxyFactory>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
namespace Mirall {
|
|
||||||
|
|
||||||
void csyncLogCatcher(CSYNC *ctx,
|
|
||||||
int verbosity,
|
|
||||||
const char *function,
|
|
||||||
const char *buffer,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString replaceScheme(const QString &urlStr)
|
|
||||||
{
|
|
||||||
|
|
||||||
QUrl url( urlStr );
|
|
||||||
if( url.scheme() == QLatin1String("http") ) {
|
|
||||||
url.setScheme( QLatin1String("owncloud") );
|
|
||||||
} else {
|
|
||||||
// connect SSL!
|
|
||||||
url.setScheme( QLatin1String("ownclouds") );
|
|
||||||
}
|
|
||||||
return url.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
ownCloudFolder::ownCloudFolder(const QString &alias,
|
|
||||||
const QString &mpath,
|
|
||||||
const QString &secondPath,
|
|
||||||
QObject *parent)
|
|
||||||
: Folder(alias, mpath, secondPath, parent)
|
|
||||||
, _thread(0)
|
|
||||||
, _csync(0)
|
|
||||||
, _csyncError(false)
|
|
||||||
, _csyncUnavail(false)
|
|
||||||
{
|
|
||||||
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
|
||||||
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
|
||||||
connect(this, SIGNAL(syncFinished(SyncResult)), notifier, SLOT(slotSyncFinished(SyncResult)));
|
|
||||||
qDebug() << "****** ownCloud folder using watcher *******";
|
|
||||||
// The folder interval is set in the folder parent class.
|
|
||||||
|
|
||||||
QString url = replaceScheme(secondPath);
|
|
||||||
QString localpath = path();
|
|
||||||
|
|
||||||
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
|
|
||||||
qDebug() << "Unable to create csync-context!";
|
|
||||||
_csync_ctx = 0;
|
|
||||||
} else {
|
|
||||||
csync_set_log_callback( _csync_ctx, csyncLogCatcher );
|
|
||||||
csync_set_log_verbosity(_csync_ctx, 11);
|
|
||||||
|
|
||||||
MirallConfigFile cfgFile;
|
|
||||||
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
|
|
||||||
|
|
||||||
csync_enable_conflictcopys(_csync_ctx);
|
|
||||||
QString excludeList = cfgFile.excludeFile();
|
|
||||||
if( !excludeList.isEmpty() ) {
|
|
||||||
qDebug() << "==== added CSync exclude List: " << excludeList.toUtf8();
|
|
||||||
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
|
|
||||||
}
|
|
||||||
csync_set_auth_callback( _csync_ctx, getauth );
|
|
||||||
|
|
||||||
if( csync_init( _csync_ctx ) < 0 ) {
|
|
||||||
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
|
|
||||||
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
|
|
||||||
csync_destroy(_csync_ctx);
|
|
||||||
_csync_ctx = 0;
|
|
||||||
}
|
|
||||||
setProxy();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ownCloudFolder::~ownCloudFolder()
|
|
||||||
{
|
|
||||||
if( _thread ) {
|
|
||||||
_thread->quit();
|
|
||||||
csync_request_abort(_csync_ctx);
|
|
||||||
_thread->wait();
|
|
||||||
}
|
|
||||||
delete _csync;
|
|
||||||
// Destroy csync here.
|
|
||||||
csync_destroy(_csync_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::setProxy()
|
|
||||||
{
|
|
||||||
if( _csync_ctx ) {
|
|
||||||
/* Store proxy */
|
|
||||||
MirallConfigFile cfgFile;
|
|
||||||
QUrl proxyUrl(cfgFile.ownCloudUrl());
|
|
||||||
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(proxyUrl);
|
|
||||||
// We set at least one in Application
|
|
||||||
Q_ASSERT(proxies.count() > 0);
|
|
||||||
QNetworkProxy proxy = proxies.first();
|
|
||||||
if (proxy.type() == QNetworkProxy::NoProxy) {
|
|
||||||
qDebug() << "Passing NO proxy to csync for" << cfgFile.ownCloudUrl();
|
|
||||||
} else {
|
|
||||||
qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type()
|
|
||||||
<< " to csync for" << cfgFile.ownCloudUrl();
|
|
||||||
}
|
|
||||||
int proxyPort = proxy.port();
|
|
||||||
|
|
||||||
csync_set_module_property(_csync_ctx, "proxy_type", (char*) proxyTypeToCStr(proxy.type()) );
|
|
||||||
csync_set_module_property(_csync_ctx, "proxy_host", proxy.hostName().toUtf8().data() );
|
|
||||||
csync_set_module_property(_csync_ctx, "proxy_port", &proxyPort );
|
|
||||||
csync_set_module_property(_csync_ctx, "proxy_user", proxy.user().toUtf8().data() );
|
|
||||||
csync_set_module_property(_csync_ctx, "proxy_pwd" , proxy.password().toUtf8().data() );
|
|
||||||
|
|
||||||
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ownCloudFolder::proxyTypeToCStr(QNetworkProxy::ProxyType type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case QNetworkProxy::NoProxy:
|
|
||||||
return "NoProxy";
|
|
||||||
case QNetworkProxy::DefaultProxy:
|
|
||||||
return "DefaultProxy";
|
|
||||||
case QNetworkProxy::Socks5Proxy:
|
|
||||||
return "Socks5Proxy";
|
|
||||||
case QNetworkProxy::HttpProxy:
|
|
||||||
return "HttpProxy";
|
|
||||||
case QNetworkProxy::HttpCachingProxy:
|
|
||||||
return "HttpCachingProxy";
|
|
||||||
case QNetworkProxy::FtpCachingProxy:
|
|
||||||
return "FtpCachingProxy";
|
|
||||||
default:
|
|
||||||
return "NoProxy";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ownCloudFolder::getauth(const char *prompt,
|
|
||||||
char *buf,
|
|
||||||
size_t len,
|
|
||||||
int echo,
|
|
||||||
int verify,
|
|
||||||
void *userdata
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int re = 0;
|
|
||||||
QMutex mutex;
|
|
||||||
|
|
||||||
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
|
|
||||||
QString user = CredentialStore::instance()->user();
|
|
||||||
QString pwd = CredentialStore::instance()->password();
|
|
||||||
|
|
||||||
if( qPrompt == QLatin1String("Enter your username:") ) {
|
|
||||||
// qDebug() << "OOO Username requested!";
|
|
||||||
QMutexLocker locker( &mutex );
|
|
||||||
qstrncpy( buf, user.toUtf8().constData(), len );
|
|
||||||
} else if( qPrompt == QLatin1String("Enter your password:") ) {
|
|
||||||
QMutexLocker locker( &mutex );
|
|
||||||
// qDebug() << "OOO Password requested!";
|
|
||||||
qstrncpy( buf, pwd.toUtf8().constData(), len );
|
|
||||||
} else {
|
|
||||||
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
|
|
||||||
// SSL is requested. If the program came here, the SSL check was done by mirall
|
|
||||||
// It needs to be checked if the chain is still equal to the one which
|
|
||||||
// was verified by the user.
|
|
||||||
QRegExp regexp("fingerprint: ([\\w\\d:]+)");
|
|
||||||
bool certOk = false;
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
// This is the set of certificates which QNAM accepted, so we should accept
|
|
||||||
// them as well
|
|
||||||
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
|
|
||||||
|
|
||||||
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
|
|
||||||
QString neon_fingerprint = regexp.cap(1);
|
|
||||||
|
|
||||||
foreach( const QSslCertificate& c, certs ) {
|
|
||||||
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
|
|
||||||
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
|
|
||||||
if( verified_shasum == neon_fingerprint ) {
|
|
||||||
certOk = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// certOk = false; DEBUG setting, keep disabled!
|
|
||||||
if( !certOk ) { // Problem!
|
|
||||||
qstrcpy( buf, "no" );
|
|
||||||
re = -1;
|
|
||||||
} else {
|
|
||||||
qstrcpy( buf, "yes" ); // Certificate is fine!
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << "Unknown prompt: <" << prompt << ">";
|
|
||||||
re = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool ownCloudFolder::isBusy() const
|
|
||||||
{
|
|
||||||
return ( _thread && _thread->isRunning() );
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ownCloudFolder::secondPath() const
|
|
||||||
{
|
|
||||||
QString re(Folder::secondPath());
|
|
||||||
MirallConfigFile cfg;
|
|
||||||
QString ocUrl = cfg.ownCloudUrl(QString::null, true);
|
|
||||||
if (ocUrl.endsWith(QLatin1Char('/')))
|
|
||||||
ocUrl.chop(1);
|
|
||||||
|
|
||||||
// qDebug() << "**** " << ocUrl << " <-> " << re;
|
|
||||||
if( re.startsWith( ocUrl ) ) {
|
|
||||||
re.remove( ocUrl );
|
|
||||||
}
|
|
||||||
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::startSync()
|
|
||||||
{
|
|
||||||
startSync( QStringList() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::startSync(const QStringList &pathList)
|
|
||||||
{
|
|
||||||
if (!_csync_ctx) {
|
|
||||||
qDebug() << Q_FUNC_INFO << "_csync_ctx is empty. probably because csync_init has failed.";
|
|
||||||
// the error should already be set
|
|
||||||
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_thread && _thread->isRunning()) {
|
|
||||||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_thread)
|
|
||||||
_thread->quit();
|
|
||||||
delete _csync;
|
|
||||||
delete _thread;
|
|
||||||
_errors.clear();
|
|
||||||
_csyncError = false;
|
|
||||||
_csyncUnavail = false;
|
|
||||||
|
|
||||||
MirallConfigFile cfgFile;
|
|
||||||
|
|
||||||
_syncResult.clearErrors();
|
|
||||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
|
||||||
emit syncStateChange();
|
|
||||||
|
|
||||||
|
|
||||||
qDebug() << "*** Start syncing";
|
|
||||||
_thread = new QThread(this);
|
|
||||||
_csync = new CSyncThread( _csync_ctx );
|
|
||||||
_csync->moveToThread(_thread);
|
|
||||||
|
|
||||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
|
||||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
|
||||||
|
|
||||||
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
|
||||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
|
||||||
|
|
||||||
connect(_csync, SIGNAL(started()), SLOT(slotCSyncStarted()), Qt::QueuedConnection);
|
|
||||||
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
|
||||||
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
|
|
||||||
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
|
|
||||||
|
|
||||||
//blocking connection so the message box happens in this thread, but block the csync thread.
|
|
||||||
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
|
|
||||||
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
|
|
||||||
|
|
||||||
_thread->start();
|
|
||||||
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
|
||||||
emit syncStarted();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotCSyncStarted()
|
|
||||||
{
|
|
||||||
qDebug() << " * csync thread started";
|
|
||||||
_syncResult.setStatus(SyncResult::SyncRunning);
|
|
||||||
emit syncStateChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotCSyncError(const QString& err)
|
|
||||||
{
|
|
||||||
_errors.append( err );
|
|
||||||
_csyncError = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotCsyncUnavailable()
|
|
||||||
{
|
|
||||||
_csyncUnavail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotCSyncFinished()
|
|
||||||
{
|
|
||||||
qDebug() << "-> CSync Finished slot with error " << _csyncError;
|
|
||||||
|
|
||||||
if (_csyncError) {
|
|
||||||
_syncResult.setStatus(SyncResult::Error);
|
|
||||||
|
|
||||||
qDebug() << " ** error Strings: " << _errors;
|
|
||||||
_syncResult.setErrorStrings( _errors );
|
|
||||||
qDebug() << " * owncloud csync thread finished with error";
|
|
||||||
} else if (_csyncUnavail) {
|
|
||||||
_syncResult.setStatus(SyncResult::Unavailable);
|
|
||||||
} else {
|
|
||||||
_syncResult.setStatus(SyncResult::Success);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _thread && _thread->isRunning() ) {
|
|
||||||
_thread->quit();
|
|
||||||
}
|
|
||||||
emit syncFinished( _syncResult );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
|
||||||
{
|
|
||||||
_syncResult.setSyncFileItemVector(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotTerminateSync()
|
|
||||||
{
|
|
||||||
qDebug() << "folder " << alias() << " Terminating!";
|
|
||||||
MirallConfigFile cfg;
|
|
||||||
QString configDir = cfg.configPath();
|
|
||||||
qDebug() << "csync's Config Dir: " << configDir;
|
|
||||||
|
|
||||||
if( _thread && _csync ) {
|
|
||||||
csync_request_abort(_csync_ctx);
|
|
||||||
_thread->quit();
|
|
||||||
_thread->wait();
|
|
||||||
_csync->deleteLater();
|
|
||||||
delete _thread;
|
|
||||||
_csync = 0;
|
|
||||||
_thread = 0;
|
|
||||||
csync_resume(_csync_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! configDir.isEmpty() ) {
|
|
||||||
QFile file( configDir + QLatin1String("/lock"));
|
|
||||||
if( file.exists() ) {
|
|
||||||
qDebug() << "After termination, lock file exists and gets removed.";
|
|
||||||
file.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_errors.append( tr("The CSync thread terminated.") );
|
|
||||||
_csyncError = true;
|
|
||||||
qDebug() << "-> CSync Terminated!";
|
|
||||||
slotCSyncFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotLocalPathChanged( const QString& dir )
|
|
||||||
{
|
|
||||||
QDir notifiedDir(dir);
|
|
||||||
QDir localPath( path() );
|
|
||||||
|
|
||||||
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
|
|
||||||
if( !localPath.exists() ) {
|
|
||||||
qDebug() << "XXXXXXX The sync folder root was removed!!";
|
|
||||||
if( _thread && _thread->isRunning() ) {
|
|
||||||
qDebug() << "CSync currently running, set wipe flag!!";
|
|
||||||
} else {
|
|
||||||
qDebug() << "CSync not running, wipe it now!!";
|
|
||||||
wipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "ALARM: The local path was DELETED!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This removes the csync File database if the sync folder definition is removed
|
|
||||||
// permanentely. This is needed to provide a clean startup again in case another
|
|
||||||
// local folder is synced to the same ownCloud.
|
|
||||||
// See http://bugs.owncloud.org/thebuggenie/owncloud/issues/oc-788
|
|
||||||
void ownCloudFolder::wipe()
|
|
||||||
{
|
|
||||||
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
|
|
||||||
|
|
||||||
QFile file(stateDbFile);
|
|
||||||
if( file.exists() ) {
|
|
||||||
if( !file.remove()) {
|
|
||||||
qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile;
|
|
||||||
} else {
|
|
||||||
qDebug() << "wipe: Removed csync StateDB " << stateDbFile;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << "WRN: statedb is empty, can not remove.";
|
|
||||||
}
|
|
||||||
// Check if the tmp database file also exists
|
|
||||||
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
|
|
||||||
QFile ctmpFile( ctmpName );
|
|
||||||
if( ctmpFile.exists() ) {
|
|
||||||
ctmpFile.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerActionNotifier::ServerActionNotifier(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
|
|
||||||
{
|
|
||||||
SyncFileItemVector items = result.syncFileItemVector();
|
|
||||||
if (items.count() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int newItems = 0;
|
|
||||||
int removedItems = 0;
|
|
||||||
int updatedItems = 0;
|
|
||||||
SyncFileItem firstItemNew;
|
|
||||||
SyncFileItem firstItemDeleted;
|
|
||||||
SyncFileItem firstItemUpdated;
|
|
||||||
foreach (const SyncFileItem &item, items) {
|
|
||||||
if (item._dir == SyncFileItem::Down) {
|
|
||||||
switch (item._instruction) {
|
|
||||||
case CSYNC_INSTRUCTION_NEW:
|
|
||||||
newItems++;
|
|
||||||
if (firstItemNew.isEmpty())
|
|
||||||
firstItemNew = item;
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_REMOVE:
|
|
||||||
removedItems++;
|
|
||||||
if (firstItemDeleted.isEmpty())
|
|
||||||
firstItemDeleted = item;
|
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_UPDATED:
|
|
||||||
updatedItems++;
|
|
||||||
if (firstItemUpdated.isEmpty())
|
|
||||||
firstItemUpdated = item;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// nothing.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newItems > 0) {
|
|
||||||
QString file = QDir::toNativeSeparators(firstItemNew._file);
|
|
||||||
if (newItems == 1)
|
|
||||||
emit guiLog(tr("New file available"), tr("'%1' has been synced to this machine.").arg(file));
|
|
||||||
else
|
|
||||||
emit guiLog(tr("New files available"), tr("'%1' and %n other file(s) have been synced to this machine.",
|
|
||||||
"", newItems-1).arg(file));
|
|
||||||
}
|
|
||||||
if (removedItems > 0) {
|
|
||||||
QString file = QDir::toNativeSeparators(firstItemDeleted._file);
|
|
||||||
if (removedItems == 1)
|
|
||||||
emit guiLog(tr("File removed"), tr("'%1' has been removed.").arg(file));
|
|
||||||
else
|
|
||||||
emit guiLog(tr("Files removed"), tr("'%1' and %n other file(s) have been removed.",
|
|
||||||
"", removedItems-1).arg(file));
|
|
||||||
}
|
|
||||||
if (updatedItems > 0) {
|
|
||||||
QString file = QDir::toNativeSeparators(firstItemUpdated._file);
|
|
||||||
if (updatedItems == 1)
|
|
||||||
emit guiLog(tr("File updated"), tr("'%1' has been updated.").arg(file));
|
|
||||||
else
|
|
||||||
emit guiLog(tr("Files updated"), tr("'%1' and %n other file(s) have been updated.",
|
|
||||||
"", updatedItems-1).arg(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudFolder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
|
||||||
{
|
|
||||||
QString msg = direction == SyncFileItem::Down ?
|
|
||||||
tr("This sync would remove all the files in the local sync folder '%1'.\n"
|
|
||||||
"If you or your administrator have reset your account on the server, choose "
|
|
||||||
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
|
|
||||||
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
|
||||||
"This might be because the folder was silently reconfigured, or that all "
|
|
||||||
"the file were manually removed.\n"
|
|
||||||
"Are you sure you want to perform this operation?");
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
|
||||||
msg.arg(alias()));
|
|
||||||
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
|
||||||
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
|
|
||||||
if (msgBox.exec() == -1) {
|
|
||||||
*cancel = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*cancel = msgBox.clickedButton() == keepBtn;
|
|
||||||
if (*cancel) {
|
|
||||||
wipe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // ns
|
|
||||||
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MIRALL_ownCloudFolder_H
|
|
||||||
#define MIRALL_ownCloudFolder_H
|
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "mirall/folder.h"
|
|
||||||
#include "mirall/csyncthread.h"
|
|
||||||
|
|
||||||
class QProcess;
|
|
||||||
class QTimer;
|
|
||||||
|
|
||||||
namespace Mirall {
|
|
||||||
|
|
||||||
enum SyncFileStatus_s {
|
|
||||||
STATUS_NONE,
|
|
||||||
STATUS_EVAL,
|
|
||||||
STATUS_REMOVE,
|
|
||||||
STATUS_RENAME,
|
|
||||||
STATUS_NEW,
|
|
||||||
STATUS_CONFLICT,
|
|
||||||
STATUS_IGNORE,
|
|
||||||
STATUS_SYNC,
|
|
||||||
STATUS_STAT_ERROR,
|
|
||||||
STATUS_ERROR,
|
|
||||||
STATUS_UPDATED
|
|
||||||
};
|
|
||||||
typedef SyncFileStatus_s SyncFileStatus;
|
|
||||||
|
|
||||||
class ServerActionNotifier : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ServerActionNotifier(QObject *parent = 0);
|
|
||||||
public slots:
|
|
||||||
void slotSyncFinished(const SyncResult &result);
|
|
||||||
signals:
|
|
||||||
void guiLog(const QString&, const QString&);
|
|
||||||
void sendResults();
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
class ownCloudFolder : public Folder
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ownCloudFolder(const QString &alias,
|
|
||||||
const QString &path,
|
|
||||||
const QString &secondPath, QObject *parent = 0L);
|
|
||||||
virtual ~ownCloudFolder();
|
|
||||||
QString secondPath() const;
|
|
||||||
virtual bool isBusy() const;
|
|
||||||
virtual void startSync(const QStringList &pathList);
|
|
||||||
|
|
||||||
virtual void wipe();
|
|
||||||
|
|
||||||
/* get status about a singel file. */
|
|
||||||
SyncFileStatus fileStatus( const QString& );
|
|
||||||
|
|
||||||
void setProxy();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void startSync();
|
|
||||||
void slotTerminateSync();
|
|
||||||
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void slotLocalPathChanged( const QString& );
|
|
||||||
void slotThreadTreeWalkResult(const SyncFileItemVector& );
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotCSyncStarted();
|
|
||||||
void slotCSyncError(const QString& );
|
|
||||||
void slotCsyncUnavailable();
|
|
||||||
void slotCSyncFinished();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static int getauth(const char *prompt,
|
|
||||||
char *buf,
|
|
||||||
size_t len,
|
|
||||||
int echo,
|
|
||||||
int verify,
|
|
||||||
void *userdata
|
|
||||||
);
|
|
||||||
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
|
||||||
|
|
||||||
QString _secondPath;
|
|
||||||
QThread *_thread;
|
|
||||||
CSyncThread *_csync;
|
|
||||||
QStringList _errors;
|
|
||||||
bool _csyncError;
|
|
||||||
bool _csyncUnavail;
|
|
||||||
bool _wipeDb;
|
|
||||||
SyncFileItemVector _items;
|
|
||||||
|
|
||||||
CSYNC *_csync_ctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -15,33 +15,19 @@
|
|||||||
#include "mirall/owncloudinfo.h"
|
#include "mirall/owncloudinfo.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
#include "mirall/utility.h"
|
|
||||||
#include "mirall/logger.h"
|
#include "mirall/logger.h"
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QAuthenticator>
|
#include <QAuthenticator>
|
||||||
|
|
||||||
#if QT46_IMPL
|
|
||||||
#include <QHttp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFAULT_CONNECTION QLatin1String("default");
|
#define DEFAULT_CONNECTION QLatin1String("default");
|
||||||
|
static const char WEBDAV_PATH[] = "remote.php/webdav/";
|
||||||
|
|
||||||
namespace Mirall
|
namespace Mirall
|
||||||
{
|
{
|
||||||
|
|
||||||
class oCCookieJar : public QNetworkCookieJar
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QList<QNetworkCookie> cookiesForUrl ( const QUrl & url ) const {
|
|
||||||
QList<QNetworkCookie> list;
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ownCloudInfo *ownCloudInfo::_instance = 0;
|
ownCloudInfo *ownCloudInfo::_instance = 0;
|
||||||
|
|
||||||
ownCloudInfo* ownCloudInfo::instance()
|
ownCloudInfo* ownCloudInfo::instance()
|
||||||
@@ -62,13 +48,16 @@ ownCloudInfo* ownCloudInfo::instance()
|
|||||||
|
|
||||||
ownCloudInfo::ownCloudInfo() :
|
ownCloudInfo::ownCloudInfo() :
|
||||||
QObject(0),
|
QObject(0),
|
||||||
_manager(0)
|
_manager(0),
|
||||||
|
_authAttempts(0),
|
||||||
|
_lastQuotaUsedBytes(0),
|
||||||
|
_lastQuotaTotalBytes(0)
|
||||||
{
|
{
|
||||||
_connection = Theme::instance()->appName();
|
_connection = Theme::instance()->appName();
|
||||||
connect(this, SIGNAL(guiLog(QString,QString)),
|
connect(this, SIGNAL(guiLog(QString,QString)),
|
||||||
Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
||||||
setNetworkAccessManager( new QNetworkAccessManager( this ) );
|
// this will set credentials specific qnam
|
||||||
|
setCustomConfigHandle(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam )
|
void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam )
|
||||||
@@ -83,18 +72,7 @@ void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam )
|
|||||||
connect( _manager, SIGNAL( sslErrors(QNetworkReply*, QList<QSslError>)),
|
connect( _manager, SIGNAL( sslErrors(QNetworkReply*, QList<QSslError>)),
|
||||||
this, SIGNAL(sslFailed(QNetworkReply*, QList<QSslError>)) );
|
this, SIGNAL(sslFailed(QNetworkReply*, QList<QSslError>)) );
|
||||||
|
|
||||||
// The authenticationRequired signal is not handled because the creds are set
|
|
||||||
// in the request header.
|
|
||||||
#if 0
|
|
||||||
connect( _manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
|
|
||||||
this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// no cookie jar so far.
|
|
||||||
_manager->setCookieJar(new oCCookieJar);
|
|
||||||
|
|
||||||
_certsUntrusted = false;
|
_certsUntrusted = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ownCloudInfo::~ownCloudInfo()
|
ownCloudInfo::~ownCloudInfo()
|
||||||
@@ -106,6 +84,8 @@ void ownCloudInfo::setCustomConfigHandle( const QString& handle )
|
|||||||
_configHandle = handle;
|
_configHandle = handle;
|
||||||
_authAttempts = 0; // allow a couple of tries again.
|
_authAttempts = 0; // allow a couple of tries again.
|
||||||
resetSSLUntrust();
|
resetSSLUntrust();
|
||||||
|
MirallConfigFile cfg(_configHandle);
|
||||||
|
setNetworkAccessManager (cfg.getCredentials()->getQNAM());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ownCloudInfo::isConfigured()
|
bool ownCloudInfo::isConfigured()
|
||||||
@@ -116,28 +96,32 @@ bool ownCloudInfo::isConfigured()
|
|||||||
|
|
||||||
QNetworkReply *ownCloudInfo::checkInstallation()
|
QNetworkReply *ownCloudInfo::checkInstallation()
|
||||||
{
|
{
|
||||||
|
_redirectCount = 0;
|
||||||
|
MirallConfigFile cfgFile( _configHandle );
|
||||||
|
QUrl url ( cfgFile.ownCloudUrl( _connection ) + QLatin1String("status.php") );
|
||||||
/* No authentication required for this. */
|
/* No authentication required for this. */
|
||||||
return getRequest( QLatin1String("status.php"), false );
|
return getRequest(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkReply* ownCloudInfo::getWebDAVPath( const QString& path )
|
QNetworkReply* ownCloudInfo::getWebDAVPath( const QString& path )
|
||||||
{
|
{
|
||||||
return getRequest( path, true );
|
_redirectCount = 0;
|
||||||
|
QUrl url ( webdavUrl( _connection ) + path );
|
||||||
|
QNetworkReply *reply = getRequest(url);
|
||||||
|
_directories[reply] = path;
|
||||||
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkReply* ownCloudInfo::getRequest( const QString& path, bool webdav )
|
QNetworkReply* ownCloudInfo::getRequest( const QUrl& url )
|
||||||
{
|
{
|
||||||
qDebug() << "Get Request to " << path;
|
qDebug() << "Get Request to " << url;
|
||||||
|
|
||||||
MirallConfigFile cfgFile( _configHandle );
|
|
||||||
QString url = cfgFile.ownCloudUrl( _connection, webdav ) + path;
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setUrl( QUrl( url ) );
|
request.setUrl( url );
|
||||||
setupHeaders( request, 0 );
|
setupHeaders( request, 0 );
|
||||||
|
|
||||||
QNetworkReply *reply = _manager->get( request );
|
QNetworkReply *reply = _manager->get( request );
|
||||||
connect( reply, SIGNAL(finished()), SLOT(slotReplyFinished()));
|
connect( reply, SIGNAL(finished()), SLOT(slotReplyFinished()));
|
||||||
_directories[reply] = path;
|
|
||||||
|
|
||||||
if( !_configHandle.isEmpty() ) {
|
if( !_configHandle.isEmpty() ) {
|
||||||
qDebug() << "Setting config handle " << _configHandle;
|
qDebug() << "Setting config handle " << _configHandle;
|
||||||
@@ -149,87 +133,13 @@ QNetworkReply* ownCloudInfo::getRequest( const QString& path, bool webdav )
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT46_IMPL
|
|
||||||
QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
|
|
||||||
{
|
|
||||||
qDebug() << "OCInfo Making dir " << dir;
|
|
||||||
|
|
||||||
MirallConfigFile cfgFile( _configHandle );
|
|
||||||
QUrl url = QUrl( cfgFile.ownCloudUrl( _connection, true ) + dir );
|
|
||||||
QHttp::ConnectionMode conMode = QHttp::ConnectionModeHttp;
|
|
||||||
if (url.scheme() == "https")
|
|
||||||
conMode = QHttp::ConnectionModeHttps;
|
|
||||||
|
|
||||||
QHttp* qhttp = new QHttp(QString(url.encodedHost()), conMode, 0, this);
|
|
||||||
|
|
||||||
connect(qhttp, SIGNAL(requestStarted(int)), this,SLOT(qhttpRequestStarted(int)));
|
|
||||||
connect(qhttp, SIGNAL(requestFinished(int, bool)), this,SLOT(qhttpRequestFinished(int,bool)));
|
|
||||||
connect(qhttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(qhttpResponseHeaderReceived(QHttpResponseHeader)));
|
|
||||||
//connect(qhttp, SIGNAL(authenticationRequired(QString,quint16,QAuthenticator*)), this, SLOT(qhttpAuthenticationRequired(QString,quint16,QAuthenticator*)));
|
|
||||||
QHttpRequestHeader header("MKCOL", QString(url.encodedPath()), 1,1); /* header */
|
|
||||||
header.setValue("Host", QString(url.encodedHost()));
|
|
||||||
header.setValue("User-Agent", Utility::userAgentString());
|
|
||||||
header.setValue("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
|
|
||||||
header.setValue("Accept-Language", "it,de-de;q=0.8,it-it;q=0.6,en-us;q=0.4,en;q=0.2");
|
|
||||||
header.setValue("Connection", "keep-alive");
|
|
||||||
header.setContentType("application/x-www-form-urlencoded"); //important
|
|
||||||
header.setContentLength(0);
|
|
||||||
|
|
||||||
QString con = _configHandle;
|
|
||||||
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
|
|
||||||
if( _credentials.contains(con)) {
|
|
||||||
oCICredentials creds = _credentials.value(con);
|
|
||||||
QString concatenated = creds.user + QLatin1Char(':') + creds.passwd;
|
|
||||||
const QString b(QLatin1String("Basic "));
|
|
||||||
QByteArray data = b.toLocal8Bit() + concatenated.toLocal8Bit().toBase64();
|
|
||||||
header.setValue("Authorization", data);
|
|
||||||
|
|
||||||
qhttp->setUser( creds.user, creds.passwd );
|
|
||||||
}
|
|
||||||
|
|
||||||
int david = qhttp->request(header,0,0);
|
|
||||||
//////////////// connect(davinfo, SIGNAL(dataSendProgress(int,int)), this, SLOT(SendStatus(int, int)));
|
|
||||||
/////////////////connect(davinfo, SIGNAL(done(bool)), this,SLOT(DavWake(bool)));
|
|
||||||
//connect(_http, SIGNAL(requestFinished(int, bool)), this,SLOT(qhttpRequestFinished(int,bool)));
|
|
||||||
///////////connect(davinfo, SIGNAL(responseHeaderReceived(constQHttpResponseHeader &)), this, SLOT(RegisterBackHeader(constQHttpResponseHeader &)));
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudInfo::qhttpResponseHeaderReceived(const QHttpResponseHeader& header)
|
|
||||||
{
|
|
||||||
qDebug() << "Resp:" << header.toString();
|
|
||||||
if (header.statusCode() == 201)
|
|
||||||
emit webdavColCreated( QNetworkReply::NoError );
|
|
||||||
else
|
|
||||||
qDebug() << "http request failed" << header.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudInfo::qhttpRequestStarted(int id)
|
|
||||||
{
|
|
||||||
qDebug() << "QHttp based request started " << id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ownCloudInfo::qhttpRequestFinished(int id, bool success )
|
|
||||||
{
|
|
||||||
qDebug() << "HIT!";
|
|
||||||
QHttp* qhttp = qobject_cast<QHttp*>(sender());
|
|
||||||
|
|
||||||
if( success ) {
|
|
||||||
qDebug() << "QHttp based request successful";
|
|
||||||
} else {
|
|
||||||
qDebug() << "QHttp based request failed: " << qhttp->errorString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
|
QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
|
||||||
{
|
{
|
||||||
qDebug() << "OCInfo Making dir " << dir;
|
qDebug() << "OCInfo Making dir " << dir;
|
||||||
_authAttempts = 0;
|
_authAttempts = 0;
|
||||||
MirallConfigFile cfgFile( _configHandle );
|
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
req.setUrl( QUrl( cfgFile.ownCloudUrl( _connection, true ) + dir ) );
|
req.setUrl( QUrl( webdavUrl(_connection) + dir ) );
|
||||||
QNetworkReply *reply = davRequest(QLatin1String("MKCOL"), req, 0);
|
QNetworkReply *reply = davRequest("MKCOL", req, 0);
|
||||||
|
|
||||||
// remember the confighandle used for this request
|
// remember the confighandle used for this request
|
||||||
if( ! _configHandle.isEmpty() )
|
if( ! _configHandle.isEmpty() )
|
||||||
@@ -246,6 +156,62 @@ QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QNetworkReply* ownCloudInfo::getQuotaRequest( const QString& dir )
|
||||||
|
{
|
||||||
|
QNetworkRequest req;
|
||||||
|
req.setUrl( QUrl( webdavUrl(_connection) + dir ) );
|
||||||
|
req.setRawHeader("Depth", "0");
|
||||||
|
QByteArray xml("<?xml version=\"1.0\" ?>\n"
|
||||||
|
"<d:propfind xmlns:d=\"DAV:\">\n"
|
||||||
|
" <d:prop>\n"
|
||||||
|
" <d:quota-available-bytes/>\n"
|
||||||
|
" <d:quota-used-bytes/>\n"
|
||||||
|
" <d:getetag/>"
|
||||||
|
" </d:prop>\n"
|
||||||
|
"</d:propfind>\n");
|
||||||
|
QBuffer *buf = new QBuffer;
|
||||||
|
buf->setData(xml);
|
||||||
|
buf->open(QIODevice::ReadOnly);
|
||||||
|
QNetworkReply *reply = davRequest("PROPFIND", req, buf);
|
||||||
|
buf->setParent(reply);
|
||||||
|
|
||||||
|
if( reply->error() != QNetworkReply::NoError ) {
|
||||||
|
qDebug() << "getting quota: request network error: " << reply->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect( reply, SIGNAL( finished()), SLOT(slotGetQuotaFinished()) );
|
||||||
|
connect( reply, SIGNAL( error(QNetworkReply::NetworkError)),
|
||||||
|
this, SLOT( slotError(QNetworkReply::NetworkError)));
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
QNetworkReply* ownCloudInfo::getDirectoryListing( const QString& dir )
|
||||||
|
{
|
||||||
|
QNetworkRequest req;
|
||||||
|
req.setUrl( QUrl( webdavUrl(_connection) + dir ) );
|
||||||
|
req.setRawHeader("Depth", "1");
|
||||||
|
QByteArray xml("<?xml version=\"1.0\" ?>\n"
|
||||||
|
"<d:propfind xmlns:d=\"DAV:\">\n"
|
||||||
|
" <d:prop>\n"
|
||||||
|
" <d:resourcetype/>\n"
|
||||||
|
" </d:prop>\n"
|
||||||
|
"</d:propfind>\n");
|
||||||
|
QBuffer *buf = new QBuffer;
|
||||||
|
buf->setData(xml);
|
||||||
|
buf->open(QIODevice::ReadOnly);
|
||||||
|
QNetworkReply *reply = davRequest("PROPFIND", req, buf);
|
||||||
|
buf->setParent(reply);
|
||||||
|
|
||||||
|
if( reply->error() != QNetworkReply::NoError ) {
|
||||||
|
qDebug() << "getting quota: request network error: " << reply->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect( reply, SIGNAL( finished()), SLOT(slotGetDirectoryListingFinished()) );
|
||||||
|
connect( reply, SIGNAL( error(QNetworkReply::NetworkError)),
|
||||||
|
this, SLOT( slotError(QNetworkReply::NetworkError)));
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ownCloudInfo::slotMkdirFinished()
|
void ownCloudInfo::slotMkdirFinished()
|
||||||
{
|
{
|
||||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||||
@@ -263,47 +229,90 @@ void ownCloudInfo::slotMkdirFinished()
|
|||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// FIXME: remove this later, once the new connection dialog has settled.
|
void ownCloudInfo::slotGetQuotaFinished()
|
||||||
#if 0
|
|
||||||
void ownCloudInfo::slotAuthentication( QNetworkReply *reply, QAuthenticator *auth )
|
|
||||||
{
|
{
|
||||||
if( !(auth && reply) ) return;
|
bool ok = false;
|
||||||
QString configHandle;
|
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||||
|
|
||||||
// an empty config handle is ok for the default config.
|
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
|
||||||
if( _configHandleMap.contains(reply) ) {
|
// Parse DAV response
|
||||||
configHandle = _configHandleMap[reply];
|
QXmlStreamReader reader(reply);
|
||||||
qDebug() << "Auth: Have a custom config handle: " << configHandle;
|
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Auth request to me and I am " << this;
|
qint64 quotaUsedBytes = 0;
|
||||||
_authAttempts++;
|
qint64 quotaAvailableBytes = 0;
|
||||||
MirallConfigFile cfgFile( configHandle );
|
QString etag;
|
||||||
qDebug() << "Authenticating request for " << reply->url();
|
|
||||||
if( reply->url().toString().startsWith( cfgFile.ownCloudUrl( _connection, true )) ) {
|
|
||||||
|
|
||||||
QString con = configHandle;
|
while (!reader.atEnd()) {
|
||||||
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
|
QXmlStreamReader::TokenType type = reader.readNext();
|
||||||
if( _credentials.contains(con)) {
|
if (type == QXmlStreamReader::StartElement &&
|
||||||
oCICredentials creds = _credentials.value(con);
|
reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
|
QString name = reader.name().toString();
|
||||||
auth->setUser( creds.user );
|
if (name == QLatin1String("quota-used-bytes")) {
|
||||||
auth->setPassword( creds.passwd );
|
quotaUsedBytes = reader.readElementText().toLongLong(&ok);
|
||||||
} else {
|
if (!ok) quotaUsedBytes = 0;
|
||||||
qDebug() << "Unable to get Credentials, not set!";
|
} else if (name == QLatin1String("quota-available-bytes")) {
|
||||||
reply->close();
|
quotaAvailableBytes = reader.readElementText().toLongLong(&ok);
|
||||||
|
if (!ok) quotaAvailableBytes = 0;
|
||||||
|
} else if (name == QLatin1String("getetag")) {
|
||||||
|
etag = reader.readElementText();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qint64 total = quotaUsedBytes + quotaAvailableBytes;
|
||||||
|
|
||||||
|
_lastQuotaTotalBytes = total;
|
||||||
|
_lastQuotaUsedBytes = quotaUsedBytes;
|
||||||
|
emit quotaUpdated(total, quotaUsedBytes);
|
||||||
|
_lastEtag = etag;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "WRN: attempt to authenticate to different url - attempt " <<_authAttempts;
|
_lastQuotaTotalBytes = 0;
|
||||||
}
|
_lastQuotaUsedBytes = 0;
|
||||||
if( _authAttempts > 1) {
|
|
||||||
qDebug() << "Too many attempts to authenticate. Stop request.";
|
|
||||||
reply->close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ownCloudInfo::slotGetDirectoryListingFinished()
|
||||||
|
{
|
||||||
|
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||||
|
|
||||||
|
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
|
||||||
|
// Parse DAV response
|
||||||
|
QXmlStreamReader reader(reply);
|
||||||
|
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||||
|
|
||||||
|
QStringList folders;
|
||||||
|
QString currentItem;
|
||||||
|
|
||||||
|
while (!reader.atEnd()) {
|
||||||
|
QXmlStreamReader::TokenType type = reader.readNext();
|
||||||
|
if (type == QXmlStreamReader::StartElement &&
|
||||||
|
reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
|
QString name = reader.name().toString();
|
||||||
|
if (name == QLatin1String("href")) {
|
||||||
|
currentItem = reader.readElementText();
|
||||||
|
} else if (name == QLatin1String("collection") &&
|
||||||
|
!currentItem.isEmpty()) {
|
||||||
|
folders.append(QUrl::fromEncoded(currentItem.toLatin1()).path());
|
||||||
|
currentItem.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit directoryListingUpdated(folders);
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QNetworkCookie> ownCloudInfo::getLastAuthCookies()
|
||||||
|
{
|
||||||
|
QUrl url = QUrl( webdavUrl(_connection));
|
||||||
|
QList<QNetworkCookie> cookies = _manager->cookieJar()->cookiesForUrl(url);
|
||||||
|
return cookies;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
QString ownCloudInfo::configHandle(QNetworkReply *reply)
|
QString ownCloudInfo::configHandle(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
@@ -320,20 +329,6 @@ QList<QSslCertificate> ownCloudInfo::certificateChain() const
|
|||||||
return _certificateChain;
|
return _certificateChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl ownCloudInfo::redirectUrl(const QUrl& possibleRedirectUrl,
|
|
||||||
const QUrl& oldRedirectUrl) const {
|
|
||||||
QUrl redirectUrl;
|
|
||||||
/*
|
|
||||||
* Check if the URL is empty and
|
|
||||||
* that we aren't being fooled into a infinite redirect loop.
|
|
||||||
*/
|
|
||||||
if(!possibleRedirectUrl.isEmpty() &&
|
|
||||||
possibleRedirectUrl != oldRedirectUrl) {
|
|
||||||
redirectUrl = possibleRedirectUrl;
|
|
||||||
}
|
|
||||||
return redirectUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// There have been problems with the finish-signal coming from the networkmanager.
|
// There have been problems with the finish-signal coming from the networkmanager.
|
||||||
// To avoid that, the reply-signals were connected and the data is taken from the
|
// To avoid that, the reply-signals were connected and the data is taken from the
|
||||||
@@ -354,12 +349,17 @@ void ownCloudInfo::slotReplyFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Detect redirect url
|
// Detect redirect url
|
||||||
QVariant possibleRedirUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
QUrl possibleRedirUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
/* We'll deduct if the redirection is valid in the redirectUrl function */
|
/* We'll deduct if the redirection is valid in the redirectUrl function */
|
||||||
_urlRedirectedTo = redirectUrl( possibleRedirUrl.toUrl(),
|
|
||||||
_urlRedirectedTo );
|
|
||||||
|
|
||||||
if(!_urlRedirectedTo.isEmpty()) {
|
|
||||||
|
if (!possibleRedirUrl.isEmpty() && _redirectCount++ > 10) {
|
||||||
|
// Are we in a redirect loop
|
||||||
|
qDebug() << "Redirect loop while redirecting to" << possibleRedirUrl;
|
||||||
|
possibleRedirUrl.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!possibleRedirUrl.isEmpty()) {
|
||||||
QString configHandle;
|
QString configHandle;
|
||||||
|
|
||||||
qDebug() << "Redirected to " << possibleRedirUrl;
|
qDebug() << "Redirected to " << possibleRedirUrl;
|
||||||
@@ -372,24 +372,28 @@ void ownCloudInfo::slotReplyFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString path = _directories[reply];
|
QString path = _directories[reply];
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path = QLatin1String("status.php");
|
||||||
|
} else {
|
||||||
|
path.prepend( QLatin1String(WEBDAV_PATH) );
|
||||||
|
}
|
||||||
qDebug() << "This path was redirected: " << path;
|
qDebug() << "This path was redirected: " << path;
|
||||||
|
|
||||||
MirallConfigFile cfgFile( configHandle );
|
QString newUrl = possibleRedirUrl.toString();
|
||||||
QString newUrl = _urlRedirectedTo.toString();
|
if( !path.isEmpty() && newUrl.endsWith( path )) {
|
||||||
if( newUrl.endsWith( path )) {
|
|
||||||
// cut off the trailing path
|
// cut off the trailing path
|
||||||
newUrl.chop( path.length() );
|
newUrl.chop( path.length() );
|
||||||
cfgFile.setOwnCloudUrl( _connection, newUrl );
|
_urlRedirectedTo = newUrl;
|
||||||
|
qDebug() << "Updated url to" << newUrl;
|
||||||
qDebug() << "Update the config file url to " << newUrl;
|
getRequest( possibleRedirUrl );
|
||||||
getRequest( path, false ); // FIXME: Redirect for webdav!
|
|
||||||
reply->deleteLater();
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "WRN: Path is not part of the redirect URL. NO redirect.";
|
qDebug() << "WRN: Path is not part of the redirect URL. NO redirect.";
|
||||||
}
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
_directories.remove(reply);
|
||||||
|
_configHandleMap.remove(reply);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
_urlRedirectedTo.clear();
|
|
||||||
|
|
||||||
// TODO: check if this is always the correct encoding
|
// TODO: check if this is always the correct encoding
|
||||||
const QString version = QString::fromUtf8( reply->readAll() );
|
const QString version = QString::fromUtf8( reply->readAll() );
|
||||||
@@ -439,8 +443,8 @@ void ownCloudInfo::slotReplyFinished()
|
|||||||
// get version out
|
// get version out
|
||||||
edition = val;
|
edition = val;
|
||||||
} else if(key == QLatin1String("installed")) {
|
} else if(key == QLatin1String("installed")) {
|
||||||
// Silently ignoring "installed = true" information
|
// Silently ignoring "installed = true" information
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Unknown info from ownCloud status.php: "<< key << "=" << val;
|
qDebug() << "Unknown info from ownCloud status.php: "<< key << "=" << val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,15 +459,13 @@ void ownCloudInfo::slotReplyFinished()
|
|||||||
QString dir(QLatin1String("unknown"));
|
QString dir(QLatin1String("unknown"));
|
||||||
if( _directories.contains(reply) ) {
|
if( _directories.contains(reply) ) {
|
||||||
dir = _directories[reply];
|
dir = _directories[reply];
|
||||||
_directories.remove(reply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit ownCloudDirExists( dir, reply );
|
emit ownCloudDirExists( dir, reply );
|
||||||
}
|
}
|
||||||
if( _configHandleMap.contains(reply)) {
|
|
||||||
_configHandleMap.remove(reply);
|
|
||||||
}
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
_directories.remove(reply);
|
||||||
|
_configHandleMap.remove(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ownCloudInfo::resetSSLUntrust()
|
void ownCloudInfo::resetSSLUntrust()
|
||||||
@@ -518,43 +520,11 @@ void ownCloudInfo::slotError( QNetworkReply::NetworkError err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ownCloudInfo::setCredentials( const QString& user, const QString& passwd,
|
|
||||||
const QString& configHandle )
|
|
||||||
{
|
|
||||||
QString con( configHandle );
|
|
||||||
if( configHandle.isEmpty() )
|
|
||||||
con = DEFAULT_CONNECTION;
|
|
||||||
|
|
||||||
if( _credentials.contains(con) ) {
|
|
||||||
qDebug() << "Overwriting credentials for connection " << con;
|
|
||||||
}
|
|
||||||
|
|
||||||
oCICredentials creds;
|
|
||||||
creds.user = user;
|
|
||||||
creds.passwd = passwd;
|
|
||||||
creds.connection = con;
|
|
||||||
_credentials[con] = creds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size )
|
void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size )
|
||||||
{
|
{
|
||||||
MirallConfigFile cfgFile(_configHandle );
|
QUrl url( req.url() );
|
||||||
|
|
||||||
QUrl url( cfgFile.ownCloudUrl( QString::null, false ) );
|
|
||||||
qDebug() << "Setting up host header: " << url.host();
|
qDebug() << "Setting up host header: " << url.host();
|
||||||
req.setRawHeader( QByteArray("Host"), url.host().toUtf8() );
|
|
||||||
req.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString());
|
|
||||||
|
|
||||||
QString con = _configHandle;
|
|
||||||
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
|
|
||||||
if( _credentials.contains(con)) {
|
|
||||||
oCICredentials creds = _credentials.value(con);
|
|
||||||
QString concatenated = creds.user + QLatin1Char(':') + creds.passwd;
|
|
||||||
const QString b(QLatin1String("Basic "));
|
|
||||||
QByteArray data = b.toUtf8() + concatenated.toUtf8().toBase64();
|
|
||||||
req.setRawHeader( QByteArray("Authorization"), data );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size) {
|
if (size) {
|
||||||
req.setHeader( QNetworkRequest::ContentLengthHeader, size);
|
req.setHeader( QNetworkRequest::ContentLengthHeader, size);
|
||||||
@@ -562,18 +532,92 @@ void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT46_IMPL
|
QNetworkReply* ownCloudInfo::davRequest(const QByteArray& reqVerb, QNetworkRequest& req, QIODevice *data)
|
||||||
#else
|
|
||||||
QNetworkReply* ownCloudInfo::davRequest(const QString& reqVerb, QNetworkRequest& req, QByteArray *data)
|
|
||||||
{
|
{
|
||||||
setupHeaders(req, quint64(data ? data->size() : 0));
|
setupHeaders(req, quint64(data ? data->size() : 0));
|
||||||
if( data ) {
|
return _manager->sendCustomRequest(req, reqVerb, data );
|
||||||
QBuffer iobuf( data );
|
|
||||||
return _manager->sendCustomRequest(req, reqVerb.toUtf8(), &iobuf );
|
|
||||||
} else {
|
|
||||||
return _manager->sendCustomRequest(req, reqVerb.toUtf8(), 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ownCloudInfo::webdavUrl(const QString &connection)
|
||||||
|
{
|
||||||
|
QString url;
|
||||||
|
|
||||||
|
if (!_urlRedirectedTo.isEmpty()) {
|
||||||
|
url = _urlRedirectedTo.toString();
|
||||||
|
} else {
|
||||||
|
MirallConfigFile cfgFile(_configHandle );
|
||||||
|
url = cfgFile.ownCloudUrl( connection );
|
||||||
|
}
|
||||||
|
url.append( QLatin1String( WEBDAV_PATH ) );
|
||||||
|
if (!url.endsWith('/')) url.append('/');
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestEtagJob::RequestEtagJob(const QString& dir, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
QNetworkRequest req;
|
||||||
|
req.setUrl( QUrl( ownCloudInfo::instance()->webdavUrl(ownCloudInfo::instance()->_connection) + dir ) );
|
||||||
|
if (dir.isEmpty() || dir == "/") {
|
||||||
|
/* For the root directory, we need to query the etags of all the sub directories
|
||||||
|
* because, at the time I am writing this comment (Owncloud 5.0.9), the etag of the
|
||||||
|
* root directory is not updated when the sub directories changes */
|
||||||
|
req.setRawHeader("Depth", "1");
|
||||||
|
} else {
|
||||||
|
req.setRawHeader("Depth", "0");
|
||||||
|
}
|
||||||
|
QByteArray xml("<?xml version=\"1.0\" ?>\n"
|
||||||
|
"<d:propfind xmlns:d=\"DAV:\">\n"
|
||||||
|
" <d:prop>\n"
|
||||||
|
" <d:getetag/>"
|
||||||
|
" </d:prop>\n"
|
||||||
|
"</d:propfind>\n");
|
||||||
|
QBuffer *buf = new QBuffer;
|
||||||
|
buf->setData(xml);
|
||||||
|
buf->open(QIODevice::ReadOnly);
|
||||||
|
_reply = ownCloudInfo::instance()->davRequest("PROPFIND", req, buf);
|
||||||
|
buf->setParent(_reply);
|
||||||
|
|
||||||
|
if( _reply->error() != QNetworkReply::NoError ) {
|
||||||
|
qDebug() << "getting etag: request network error: " << _reply->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect( _reply, SIGNAL( finished()), SLOT(slotFinished()) );
|
||||||
|
connect( _reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||||
|
this, SLOT(slotError()));
|
||||||
|
connect( _reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||||
|
ownCloudInfo::instance(), SLOT(slotError(QNetworkReply::NetworkError)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestEtagJob::slotFinished()
|
||||||
|
{
|
||||||
|
if (_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
|
||||||
|
// Parse DAV response
|
||||||
|
QXmlStreamReader reader(_reply);
|
||||||
|
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||||
|
QString etag;
|
||||||
|
while (!reader.atEnd()) {
|
||||||
|
QXmlStreamReader::TokenType type = reader.readNext();
|
||||||
|
if (type == QXmlStreamReader::StartElement &&
|
||||||
|
reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
|
QString name = reader.name().toString();
|
||||||
|
if (name == QLatin1String("getetag")) {
|
||||||
|
etag += reader.readElementText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit etagRetreived(etag);
|
||||||
|
}
|
||||||
|
_reply->deleteLater();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestEtagJob::slotError()
|
||||||
|
{
|
||||||
|
qDebug() << "RequestEtagJob Error: " << _reply->errorString();
|
||||||
|
_reply->deleteLater();
|
||||||
|
deleteLater();
|
||||||
|
emit networkError();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|||||||
@@ -18,21 +18,9 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtNetwork>
|
#include <QtNetwork>
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040700
|
|
||||||
#define QT46_IMPL 0
|
|
||||||
#else
|
|
||||||
#define QT46_IMPL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Mirall
|
namespace Mirall
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
QString user;
|
|
||||||
QString passwd;
|
|
||||||
QString connection;
|
|
||||||
} oCICredentials;
|
|
||||||
|
|
||||||
class ownCloudInfo : public QObject
|
class ownCloudInfo : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -47,12 +35,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
QNetworkReply* checkInstallation();
|
QNetworkReply* checkInstallation();
|
||||||
|
|
||||||
/**
|
|
||||||
* a general GET request to the ownCloud. If the second bool parameter is
|
|
||||||
* true, the WebDAV server is queried.
|
|
||||||
*/
|
|
||||||
QNetworkReply* getRequest( const QString&, bool );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convenience: GET request to the WebDAV server.
|
* convenience: GET request to the WebDAV server.
|
||||||
*/
|
*/
|
||||||
@@ -87,6 +69,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
QNetworkReply* mkdirRequest( const QString& );
|
QNetworkReply* mkdirRequest( const QString& );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve quota for a path. Provide a relative path.
|
||||||
|
*/
|
||||||
|
QNetworkReply* getQuotaRequest( const QString& );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide collections in a directory via owncloud. Provide a relative path.
|
||||||
|
*/
|
||||||
|
QNetworkReply* getDirectoryListing( const QString& dir );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use a custom ownCloud configuration file identified by handle
|
* Use a custom ownCloud configuration file identified by handle
|
||||||
*/
|
*/
|
||||||
@@ -104,11 +96,17 @@ public:
|
|||||||
QList<QSslCertificate> certificateChain() const;
|
QList<QSslCertificate> certificateChain() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store credentials for a given connection. Empty connection parameter
|
* returns the owncloud webdav url.
|
||||||
* means "default connection".
|
* It may be different from the one in the config if there was a HTTP redirection
|
||||||
|
* The returned URL is guaranteed to end in a forward slash ('/')
|
||||||
*/
|
*/
|
||||||
void setCredentials( const QString&, const QString&,
|
QString webdavUrl(const QString& connection = QString());
|
||||||
const QString& configHandle = QString::null );
|
|
||||||
|
qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; }
|
||||||
|
qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; }
|
||||||
|
QString lastEtag() const { return _lastEtag; }
|
||||||
|
|
||||||
|
QList<QNetworkCookie> getLastAuthCookies();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// result signal with url- and version string.
|
// result signal with url- and version string.
|
||||||
@@ -119,34 +117,29 @@ signals:
|
|||||||
void webdavColCreated( QNetworkReply::NetworkError );
|
void webdavColCreated( QNetworkReply::NetworkError );
|
||||||
void sslFailed( QNetworkReply *reply, QList<QSslError> errors );
|
void sslFailed( QNetworkReply *reply, QList<QSslError> errors );
|
||||||
void guiLog( const QString& title, const QString& content );
|
void guiLog( const QString& title, const QString& content );
|
||||||
public slots:
|
void quotaUpdated( qint64 total, qint64 quotaUsedBytes );
|
||||||
|
void directoryListingUpdated(const QStringList &directories);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotReplyFinished( );
|
void slotReplyFinished( );
|
||||||
void slotError( QNetworkReply::NetworkError );
|
void slotError( QNetworkReply::NetworkError );
|
||||||
// void slotAuthentication( QNetworkReply*, QAuthenticator *);
|
|
||||||
|
|
||||||
#if QT46_IMPL
|
|
||||||
void qhttpRequestFinished(int id, bool success );
|
|
||||||
void qhttpRequestStarted(int id);
|
|
||||||
void qhttpResponseHeaderReceived(const QHttpResponseHeader& header);
|
|
||||||
// void qhttpAuthenticationRequired(const QString& hostname, quint16 port ,QAuthenticator* authenticator);
|
|
||||||
#else
|
|
||||||
void slotMkdirFinished();
|
void slotMkdirFinished();
|
||||||
#endif
|
void slotGetQuotaFinished();
|
||||||
|
void slotGetDirectoryListingFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ownCloudInfo();
|
explicit ownCloudInfo();
|
||||||
|
|
||||||
QUrl redirectUrl(const QUrl&, const QUrl& ) const;
|
/**
|
||||||
|
* a general GET request to the ownCloud WebDAV.
|
||||||
|
*/
|
||||||
|
QNetworkReply* getRequest( const QUrl &url);
|
||||||
|
QNetworkReply* davRequest(const QByteArray&, QNetworkRequest&, QIODevice* );
|
||||||
|
|
||||||
~ownCloudInfo();
|
~ownCloudInfo();
|
||||||
|
|
||||||
void setupHeaders(QNetworkRequest &req, quint64 size );
|
void setupHeaders(QNetworkRequest &req, quint64 size );
|
||||||
#if QT46_IMPL
|
|
||||||
#else
|
|
||||||
QNetworkReply* davRequest(const QString&, QNetworkRequest&, QByteArray* );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static ownCloudInfo *_instance;
|
static ownCloudInfo *_instance;
|
||||||
|
|
||||||
@@ -159,10 +152,35 @@ private:
|
|||||||
QList<QSslCertificate> _certificateChain;
|
QList<QSslCertificate> _certificateChain;
|
||||||
bool _certsUntrusted;
|
bool _certsUntrusted;
|
||||||
int _authAttempts;
|
int _authAttempts;
|
||||||
QMap<QString, oCICredentials> _credentials;
|
|
||||||
QMutex _certChainMutex;
|
QMutex _certChainMutex;
|
||||||
|
int _redirectCount;
|
||||||
|
qint64 _lastQuotaUsedBytes;
|
||||||
|
qint64 _lastQuotaTotalBytes;
|
||||||
|
QString _lastEtag;
|
||||||
|
|
||||||
|
friend class RequestEtagJob;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RequestEtagJob : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QNetworkReply *_reply;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RequestEtagJob(const QString &dir , QObject* parent = 0);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotFinished();
|
||||||
|
void slotError();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void etagRetreived(const QString &etag);
|
||||||
|
void networkError();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|
||||||
#endif // OWNCLOUDINFO_H
|
#endif // OWNCLOUDINFO_H
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -12,39 +13,44 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QAbstractButton>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
|
||||||
|
#include "wizard/owncloudwizardcommon.h"
|
||||||
|
#include "wizard/owncloudwizard.h"
|
||||||
#include "mirall/owncloudsetupwizard.h"
|
#include "mirall/owncloudsetupwizard.h"
|
||||||
#include "mirall/mirallconfigfile.h"
|
#include "mirall/mirallconfigfile.h"
|
||||||
#include "mirall/owncloudinfo.h"
|
#include "mirall/owncloudinfo.h"
|
||||||
#include "mirall/folderman.h"
|
#include "mirall/folderman.h"
|
||||||
#include "mirall/credentialstore.h"
|
|
||||||
#include "mirall/utility.h"
|
#include "mirall/utility.h"
|
||||||
|
#include "mirall/mirallaccessmanager.h"
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
#include "creds/dummycredentials.h"
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
class Theme;
|
OwncloudSetupWizard::OwncloudSetupWizard(QObject* parent) :
|
||||||
|
|
||||||
OwncloudSetupWizard::OwncloudSetupWizard( FolderMan *folderMan, Theme *theme, QObject *parent ) :
|
|
||||||
QObject( parent ),
|
QObject( parent ),
|
||||||
_mkdirRequestReply(0),
|
_ocWizard(new OwncloudWizard),
|
||||||
_checkInstallationRequest(0),
|
_mkdirRequestReply(),
|
||||||
_folderMan(folderMan)
|
_checkInstallationRequest(),
|
||||||
|
_checkRemoteFolderRequest(),
|
||||||
|
_configHandle(),
|
||||||
|
_remoteFolder()
|
||||||
{
|
{
|
||||||
_ocWizard = new OwncloudWizard();
|
connect( _ocWizard, SIGNAL(determineAuthType(const QString&)),
|
||||||
|
this, SLOT(slotDetermineAuthType(const QString&)));
|
||||||
connect( _ocWizard, SIGNAL(connectToOCUrl( const QString& ) ),
|
connect( _ocWizard, SIGNAL(connectToOCUrl( const QString& ) ),
|
||||||
this, SLOT(slotConnectToOCUrl( const QString& )));
|
this, SLOT(slotConnectToOCUrl( const QString& )));
|
||||||
|
connect( _ocWizard, SIGNAL(createLocalAndRemoteFolders(QString, QString)),
|
||||||
|
this, SLOT(slotCreateLocalAndRemoteFolders(QString, QString)));
|
||||||
connect( _ocWizard, SIGNAL(finished(int)),this,SLOT(slotAssistantFinished(int)));
|
connect( _ocWizard, SIGNAL(finished(int)),this,SLOT(slotAssistantFinished(int)));
|
||||||
|
|
||||||
connect( _ocWizard, SIGNAL(clearPendingRequests()),
|
connect( _ocWizard, SIGNAL(clearPendingRequests()),
|
||||||
this, SLOT(slotClearPendingRequests()));
|
this, SLOT(slotClearPendingRequests()));
|
||||||
|
|
||||||
_ocWizard->setWindowTitle( tr("%1 Connection Wizard").arg( theme->appNameGUI() ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OwncloudSetupWizard::~OwncloudSetupWizard()
|
OwncloudSetupWizard::~OwncloudSetupWizard()
|
||||||
@@ -52,8 +58,12 @@ OwncloudSetupWizard::~OwncloudSetupWizard()
|
|||||||
_ocWizard->deleteLater();
|
_ocWizard->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
OwncloudWizard *OwncloudSetupWizard::wizard() {
|
void OwncloudSetupWizard::runWizard(QObject* obj, const char* amember, QWidget *parent)
|
||||||
return _ocWizard;
|
{
|
||||||
|
OwncloudSetupWizard *wiz = new OwncloudSetupWizard(parent);
|
||||||
|
connect( wiz, SIGNAL(ownCloudWizardDone(int)), obj, amember);
|
||||||
|
FolderMan::instance()->setSyncEnabled(false);
|
||||||
|
wiz->startWizard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::startWizard()
|
void OwncloudSetupWizard::startWizard()
|
||||||
@@ -62,14 +72,10 @@ void OwncloudSetupWizard::startWizard()
|
|||||||
MirallConfigFile cfgFile;
|
MirallConfigFile cfgFile;
|
||||||
// Fill the entry fields with existing values.
|
// Fill the entry fields with existing values.
|
||||||
QString url = cfgFile.ownCloudUrl();
|
QString url = cfgFile.ownCloudUrl();
|
||||||
QString user = cfgFile.ownCloudUser();
|
//QString user = cfgFile.ownCloudUser();
|
||||||
bool configExists = !( url.isEmpty() || user.isEmpty() );
|
bool configExists = !( url.isEmpty()/* || user.isEmpty()*/ );
|
||||||
_ocWizard->setConfigExists( configExists );
|
_ocWizard->setConfigExists( configExists );
|
||||||
|
|
||||||
if( !user.isEmpty() ) {
|
|
||||||
_ocWizard->setOCUser( user );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !url.isEmpty() ) {
|
if( !url.isEmpty() ) {
|
||||||
_ocWizard->setOCUrl( url );
|
_ocWizard->setOCUrl( url );
|
||||||
}
|
}
|
||||||
@@ -80,133 +86,30 @@ void OwncloudSetupWizard::startWizard()
|
|||||||
QString localFolder = Theme::instance()->defaultClientFolder();
|
QString localFolder = Theme::instance()->defaultClientFolder();
|
||||||
|
|
||||||
// if its a relative path, prepend with users home dir, otherwise use as absolute path
|
// if its a relative path, prepend with users home dir, otherwise use as absolute path
|
||||||
if( !localFolder.startsWith(QLatin1Char('/')) ) {
|
if( !QDir(localFolder).isAbsolute() ) {
|
||||||
localFolder = QDir::homePath() + QDir::separator() + Theme::instance()->defaultClientFolder();
|
localFolder = QDir::homePath() + QDir::separator() + localFolder;
|
||||||
}
|
}
|
||||||
_ocWizard->setProperty("localFolder", localFolder);
|
_ocWizard->setProperty("localFolder", localFolder);
|
||||||
_ocWizard->setRemoteFolder(_remoteFolder);
|
_ocWizard->setRemoteFolder(_remoteFolder);
|
||||||
|
|
||||||
_ocWizard->setStartId(OwncloudWizard::Page_oCSetup);
|
_ocWizard->setStartId(WizardCommon::Page_ServerSetup);
|
||||||
|
|
||||||
_ocWizard->restart();
|
_ocWizard->restart();
|
||||||
|
|
||||||
// settings re-initialized in initPage must be set here after restart
|
// settings re-initialized in initPage must be set here after restart
|
||||||
_ocWizard->setMultipleFoldersExist(_folderMan->map().count() > 1);
|
_ocWizard->setMultipleFoldersExist(FolderMan::instance()->map().count() > 1);
|
||||||
|
|
||||||
_ocWizard->show();
|
_ocWizard->open();
|
||||||
_ocWizard->raise();
|
_ocWizard->raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotDetermineAuthType(const QString& serverUrl)
|
||||||
// Method executed when the user ends the wizard, either with 'accept' or 'reject'.
|
|
||||||
// accept the custom config to be the main one if Accepted.
|
|
||||||
void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|
||||||
{
|
|
||||||
MirallConfigFile cfg( _configHandle );
|
|
||||||
|
|
||||||
|
|
||||||
if( result == QDialog::Rejected ) {
|
|
||||||
// the old config remains valid. Remove the temporary one.
|
|
||||||
cfg.cleanupCustomConfig();
|
|
||||||
qDebug() << "Rejected the new config, use the old!";
|
|
||||||
} else if( result == QDialog::Accepted ) {
|
|
||||||
qDebug() << "Config Changes were accepted!";
|
|
||||||
|
|
||||||
// go through all folders and remove the journals if the server changed.
|
|
||||||
MirallConfigFile prevCfg;
|
|
||||||
QUrl prevUrl( prevCfg.ownCloudUrl() );
|
|
||||||
QUrl newUrl( cfg.ownCloudUrl() );
|
|
||||||
|
|
||||||
bool urlHasChanged = (prevUrl.host() != newUrl.host() || prevUrl.path() != newUrl.path());
|
|
||||||
|
|
||||||
// if the user changed, its also a changed url.
|
|
||||||
if( prevCfg.ownCloudUser() != cfg.ownCloudUser() ) {
|
|
||||||
urlHasChanged = true;
|
|
||||||
qDebug() << "The User has changed, same as url change.";
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString localFolder = _ocWizard->localFolder();
|
|
||||||
bool acceptCfg = true;
|
|
||||||
|
|
||||||
if( urlHasChanged ) {
|
|
||||||
_folderMan->unloadAllFolders();
|
|
||||||
|
|
||||||
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
|
||||||
if( startFromScratch ) {
|
|
||||||
// first try to rename (backup) the current local dir.
|
|
||||||
bool renameOk = false;
|
|
||||||
while( !renameOk ) {
|
|
||||||
renameOk = _folderMan->startFromScratch(localFolder);
|
|
||||||
if( ! renameOk ) {
|
|
||||||
QMessageBox::StandardButton but;
|
|
||||||
but = QMessageBox::question( 0, tr("Folder rename failed"),
|
|
||||||
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
|
|
||||||
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
|
|
||||||
if( but == QMessageBox::Abort ) {
|
|
||||||
renameOk = true;
|
|
||||||
acceptCfg = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// save the user credentials and afterwards clear the cred store.
|
|
||||||
if( acceptCfg ) {
|
|
||||||
cfg.acceptCustomConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now write the resulting folder definition if folder names are set.
|
|
||||||
if( acceptCfg && urlHasChanged ) {
|
|
||||||
_folderMan->removeAllFolderDefinitions();
|
|
||||||
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
|
|
||||||
localFolder, _remoteFolder, false );
|
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
|
||||||
} else {
|
|
||||||
// url is unchanged. Only the password was changed.
|
|
||||||
if( acceptCfg ) {
|
|
||||||
qDebug() << "Only password was changed, no changes to folder configuration.";
|
|
||||||
} else {
|
|
||||||
qDebug() << "User interrupted change of configuration.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the custom config handle
|
|
||||||
_configHandle.clear();
|
|
||||||
ownCloudInfo::instance()->setCustomConfigHandle( QString::null );
|
|
||||||
|
|
||||||
// notify others.
|
|
||||||
emit ownCloudWizardDone( result );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
|
|
||||||
{
|
|
||||||
qDebug() << "Connect to url: " << url;
|
|
||||||
_ocWizard->setField(QLatin1String("OCUrl"), url );
|
|
||||||
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
|
|
||||||
.arg( Theme::instance()->appNameGUI() ).arg(url) );
|
|
||||||
testOwnCloudConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotClearPendingRequests()
|
|
||||||
{
|
|
||||||
qDebug() << "Pending request: " << _mkdirRequestReply;
|
|
||||||
if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) {
|
|
||||||
qDebug() << "ABORTing pending mkdir request.";
|
|
||||||
_mkdirRequestReply->abort();
|
|
||||||
}
|
|
||||||
if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) {
|
|
||||||
qDebug() << "ABORTing pending check installation request.";
|
|
||||||
_checkInstallationRequest->abort();
|
|
||||||
}
|
|
||||||
if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) {
|
|
||||||
qDebug() << "ABORTing pending remote folder check request.";
|
|
||||||
_checkRemoteFolderRequest->abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupWizard::testOwnCloudConnect()
|
|
||||||
{
|
{
|
||||||
|
QString url(serverUrl);
|
||||||
|
qDebug() << "Connect to url: " << url;
|
||||||
|
_ocWizard->setField(QLatin1String("OCUrl"), url );
|
||||||
|
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 to determine authentication type...")
|
||||||
|
.arg( Theme::instance()->appNameGUI() ).arg(url) );
|
||||||
// write a temporary config.
|
// write a temporary config.
|
||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@@ -219,8 +122,7 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
|||||||
|
|
||||||
_configHandle = now.toString(QLatin1String("MMddyyhhmmss"));
|
_configHandle = now.toString(QLatin1String("MMddyyhhmmss"));
|
||||||
|
|
||||||
MirallConfigFile cfgFile( _configHandle );
|
MirallConfigFile cfgFile( _configHandle, true );
|
||||||
QString url = _ocWizard->field(QLatin1String("OCUrl")).toString();
|
|
||||||
if( url.isEmpty() ) return;
|
if( url.isEmpty() ) return;
|
||||||
if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) {
|
if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) {
|
||||||
qDebug() << "url does not start with a valid protocol, assuming https.";
|
qDebug() << "url does not start with a valid protocol, assuming https.";
|
||||||
@@ -230,50 +132,87 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
|||||||
}
|
}
|
||||||
cfgFile.writeOwncloudConfig( Theme::instance()->appName(),
|
cfgFile.writeOwncloudConfig( Theme::instance()->appName(),
|
||||||
url,
|
url,
|
||||||
_ocWizard->field(QLatin1String("OCUser")).toString(),
|
new DummyCredentials);
|
||||||
_ocWizard->field(QLatin1String("OCPasswd")).toString() );
|
|
||||||
|
|
||||||
// If there is already a config, take its proxy config.
|
|
||||||
if( ownCloudInfo::instance()->isConfigured() ) {
|
|
||||||
MirallConfigFile prevCfg;
|
|
||||||
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
|
|
||||||
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// now start ownCloudInfo to check the connection.
|
|
||||||
ownCloudInfo* info = ownCloudInfo::instance();
|
ownCloudInfo* info = ownCloudInfo::instance();
|
||||||
info->setCustomConfigHandle( _configHandle );
|
info->setCustomConfigHandle( _configHandle );
|
||||||
if( info->isConfigured() ) {
|
if( info->isConfigured() ) {
|
||||||
// reset the SSL Untrust flag to let the SSL dialog appear again.
|
// reset the SSL Untrust flag to let the SSL dialog appear again.
|
||||||
info->resetSSLUntrust();
|
info->resetSSLUntrust();
|
||||||
connect(info, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
connect(info, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
||||||
SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
|
SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString)));
|
||||||
connect(info, SIGNAL(noOwncloudFound(QNetworkReply*)),
|
connect(info, SIGNAL(noOwncloudFound(QNetworkReply*)),
|
||||||
SLOT(slotNoOwnCloudFound(QNetworkReply*)));
|
SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*)));
|
||||||
_checkInstallationRequest = info->checkInstallation();
|
_checkInstallationRequest = info->checkInstallation();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << " ownCloud seems not to be configured, can not start test connect.";
|
qDebug() << " ownCloud seems not to be configured, can not start test connect.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotOwnCloudFound( const QString& url, const QString& infoString, const QString& version, const QString& )
|
void OwncloudSetupWizard::slotOwnCloudFoundAuth( const QString& url, const QString& infoString, const QString& version, const QString& )
|
||||||
{
|
{
|
||||||
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
||||||
this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
|
this, SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString)));
|
||||||
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
|
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
|
||||||
this, SLOT(slotNoOwnCloudFound(QNetworkReply*)));
|
this, SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*)));
|
||||||
|
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>")
|
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>")
|
||||||
.arg( url ).arg(Theme::instance()->appNameGUI()).arg(infoString).arg(version));
|
.arg( url ).arg(Theme::instance()->appNameGUI()).arg(infoString).arg(version));
|
||||||
|
|
||||||
// enable the finish button.
|
MirallAccessManager* nm = new MirallAccessManager(this);
|
||||||
_ocWizard->button( QWizard::FinishButton )->setEnabled( true );
|
// TODO: We should get this path from owncloud info.
|
||||||
|
QNetworkReply* reply = nm->get (QNetworkRequest (url + "/remote.php/webdav/"));
|
||||||
|
|
||||||
// start the local folder creation
|
connect (reply, SIGNAL(finished()),
|
||||||
setupLocalSyncFolder();
|
this, SLOT(slotAuthCheckReplyFinished()));
|
||||||
|
|
||||||
|
nm->setProperty ("mirallRedirs", QVariant (0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotNoOwnCloudFound( QNetworkReply *err )
|
void OwncloudSetupWizard::slotAuthCheckReplyFinished()
|
||||||
|
{
|
||||||
|
QNetworkReply* reply = qobject_cast< QNetworkReply* > (sender ());
|
||||||
|
QUrl redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
|
QNetworkAccessManager* nm = reply->manager ();
|
||||||
|
const int redirCount = nm->property ("mirallRedirs").toInt();
|
||||||
|
|
||||||
|
if (redirCount > 10) {
|
||||||
|
redirection.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect (reply, SIGNAL(finished()),
|
||||||
|
this, SLOT(slotAuthCheckReplyFinished()));
|
||||||
|
if ((reply->error () == QNetworkReply::AuthenticationRequiredError) || redirection.isEmpty()) {
|
||||||
|
reply->deleteLater();
|
||||||
|
nm->deleteLater();
|
||||||
|
_ocWizard->setAuthType (WizardCommon::HttpCreds);
|
||||||
|
} else if (redirection.toString().endsWith ("/remote.php/webdav/")) {
|
||||||
|
QNetworkReply* newReply = nm->get (QNetworkRequest(redirection));
|
||||||
|
|
||||||
|
connect (newReply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||||
|
this, SLOT(slotAuthCheckReplyError(QNetworkReply::NetworkError)));
|
||||||
|
connect (newReply, SIGNAL(finished()),
|
||||||
|
this, SLOT(slotAuthCheckReplyFinished(QNetworkReply::NetworkError)));
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
nm->setProperty ("mirallRedirs", QVariant(redirCount + 1));
|
||||||
|
} else {
|
||||||
|
QRegExp shibbolethyWords ("SAML|wayf");
|
||||||
|
|
||||||
|
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
|
||||||
|
if (redirection.toString ().contains (shibbolethyWords)) {
|
||||||
|
_ocWizard->setAuthType(WizardCommon::Shibboleth);
|
||||||
|
} else {
|
||||||
|
// TODO: Send an error.
|
||||||
|
// eh?
|
||||||
|
_ocWizard->setAuthType (WizardCommon::HttpCreds);
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
nm->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotNoOwnCloudFoundAuth( QNetworkReply *err )
|
||||||
{
|
{
|
||||||
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
|
||||||
this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
|
this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
|
||||||
@@ -286,19 +225,81 @@ void OwncloudSetupWizard::slotNoOwnCloudFound( QNetworkReply *err )
|
|||||||
// remove the config file again
|
// remove the config file again
|
||||||
MirallConfigFile cfgFile( _configHandle );
|
MirallConfigFile cfgFile( _configHandle );
|
||||||
cfgFile.cleanupCustomConfig();
|
cfgFile.cleanupCustomConfig();
|
||||||
finalizeSetup( false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::setupLocalSyncFolder()
|
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
|
||||||
{
|
{
|
||||||
if( ! _folderMan ) return;
|
qDebug() << "Connect to url: " << url;
|
||||||
|
_ocWizard->setField(QLatin1String("OCUrl"), url );
|
||||||
|
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
|
||||||
|
.arg( Theme::instance()->appNameGUI() ).arg(url) );
|
||||||
|
testOwnCloudConnect();
|
||||||
|
}
|
||||||
|
|
||||||
const QString localFolder = _ocWizard->property("localFolder").toString();
|
void OwncloudSetupWizard::testOwnCloudConnect()
|
||||||
|
{
|
||||||
|
// write a temporary config.
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
if( _configHandle.isEmpty() ) {
|
||||||
|
_configHandle = now.toString(QLatin1String("MMddyyhhmmss"));
|
||||||
|
}
|
||||||
|
|
||||||
|
MirallConfigFile cfgFile( _configHandle, true );
|
||||||
|
QString url = _ocWizard->field(QLatin1String("OCUrl")).toString();
|
||||||
|
if( url.isEmpty() ) return;
|
||||||
|
if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) {
|
||||||
|
qDebug() << "url does not start with a valid protocol, assuming https.";
|
||||||
|
url.prepend(QLatin1String("https://"));
|
||||||
|
// FIXME: give a hint about the auto completion
|
||||||
|
_ocWizard->setOCUrl(url);
|
||||||
|
}
|
||||||
|
cfgFile.writeOwncloudConfig( Theme::instance()->appName(),
|
||||||
|
url,
|
||||||
|
_ocWizard->getCredentials());
|
||||||
|
|
||||||
|
ownCloudInfo* info(ownCloudInfo::instance());
|
||||||
|
info->setCustomConfigHandle( _configHandle );
|
||||||
|
// If there is already a config, take its proxy config.
|
||||||
|
if( info->isConfigured() ) {
|
||||||
|
MirallConfigFile prevCfg;
|
||||||
|
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
|
||||||
|
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
|
||||||
|
}
|
||||||
|
|
||||||
|
connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
||||||
|
this,SLOT(slotConnectionCheck(QString,QNetworkReply*)));
|
||||||
|
|
||||||
|
qDebug() << "# checking for authentication settings.";
|
||||||
|
_checkRemoteFolderRequest = info->getWebDAVPath(_remoteFolder ); // this call needs to be authenticated.
|
||||||
|
// continue in slotConnectionCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotConnectionCheck(const QString&, QNetworkReply* reply)
|
||||||
|
{
|
||||||
|
// disconnect from ownCloud Info signals
|
||||||
|
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
||||||
|
this, SLOT(slotConnectionCheck(QString,QNetworkReply*)));
|
||||||
|
|
||||||
|
switch (reply->error()) {
|
||||||
|
case QNetworkReply::NoError:
|
||||||
|
case QNetworkReply::ContentNotFoundError:
|
||||||
|
_ocWizard->successfulStep();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_ocWizard->displayError(tr("Error: Wrong credentials."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
|
||||||
|
{
|
||||||
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
||||||
QDir fi( localFolder );
|
const QDir fi( localFolder );
|
||||||
// FIXME: Show problems with local folder properly.
|
// FIXME: Show problems with local folder properly.
|
||||||
|
|
||||||
bool localFolderOk = true;
|
bool localFolderOk = true;
|
||||||
|
|
||||||
if( fi.exists() ) {
|
if( fi.exists() ) {
|
||||||
// there is an existing local folder. If its non empty, it can only be synced if the
|
// there is an existing local folder. If its non empty, it can only be synced if the
|
||||||
// ownCloud is newly created.
|
// ownCloud is newly created.
|
||||||
@@ -319,18 +320,19 @@ void OwncloudSetupWizard::setupLocalSyncFolder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( localFolderOk ) {
|
if( localFolderOk ) {
|
||||||
checkRemoteFolder();
|
checkRemoteFolder(remoteFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::checkRemoteFolder()
|
void OwncloudSetupWizard::checkRemoteFolder(const QString& remoteFolder)
|
||||||
{
|
{
|
||||||
connect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
ownCloudInfo* info(ownCloudInfo::instance());
|
||||||
|
connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
|
||||||
this,SLOT(slotAuthCheckReply(QString,QNetworkReply*)));
|
this,SLOT(slotAuthCheckReply(QString,QNetworkReply*)));
|
||||||
|
|
||||||
qDebug() << "# checking for authentication settings.";
|
qDebug() << "# checking for existence of remote folder.";
|
||||||
ownCloudInfo::instance()->setCustomConfigHandle(_configHandle);
|
info->setCustomConfigHandle(_configHandle);
|
||||||
_checkRemoteFolderRequest = ownCloudInfo::instance()->getRequest(_remoteFolder, true ); // this call needs to be authenticated.
|
_checkRemoteFolderRequest = info->getWebDAVPath(remoteFolder); // this call needs to be authenticated.
|
||||||
// continue in slotAuthCheckReply
|
// continue in slotAuthCheckReply
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,22 +348,12 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep
|
|||||||
|
|
||||||
if( errId == QNetworkReply::NoError ) {
|
if( errId == QNetworkReply::NoError ) {
|
||||||
qDebug() << "******** Remote folder found, all cool!";
|
qDebug() << "******** Remote folder found, all cool!";
|
||||||
} else if( errId == QNetworkReply::AuthenticationRequiredError ) { // returned if the user is wrong.
|
|
||||||
qDebug() << "******** Password is wrong!";
|
|
||||||
error = tr("The given credentials do not authenticate.");
|
|
||||||
ok = false;
|
|
||||||
} else if( errId == QNetworkReply::OperationCanceledError ) {
|
|
||||||
// the username was wrong and ownCloudInfo was closing the request after a couple of auth tries.
|
|
||||||
qDebug() << "******** Username or password is wrong!";
|
|
||||||
error = tr("Username or password is wrong!");
|
|
||||||
ok = false;
|
|
||||||
} else if( errId == QNetworkReply::ContentNotFoundError ) {
|
} else if( errId == QNetworkReply::ContentNotFoundError ) {
|
||||||
// FIXME try to create the remote folder!
|
if( createRemoteFolder() ) {
|
||||||
if( !createRemoteFolder() ) {
|
return; // Finish here, the mkdir request will go on.
|
||||||
|
} else {
|
||||||
error = tr("The remote folder could not be accessed!");
|
error = tr("The remote folder could not be accessed!");
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
|
||||||
return; // Finish here, the mkdir request will go on.
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = tr("Error: %1").arg(reply->errorString());
|
error = tr("Error: %1").arg(reply->errorString());
|
||||||
@@ -370,8 +362,6 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep
|
|||||||
|
|
||||||
if( !ok ) {
|
if( !ok ) {
|
||||||
_ocWizard->displayError(error);
|
_ocWizard->displayError(error);
|
||||||
} else {
|
|
||||||
_ocWizard->setRemoteFolder( _remoteFolder );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizeSetup( ok );
|
finalizeSetup( ok );
|
||||||
@@ -382,10 +372,11 @@ bool OwncloudSetupWizard::createRemoteFolder()
|
|||||||
if( _remoteFolder.isEmpty() ) return false;
|
if( _remoteFolder.isEmpty() ) return false;
|
||||||
|
|
||||||
_ocWizard->appendToConfigurationLog( tr("creating folder on ownCloud: %1" ).arg( _remoteFolder ));
|
_ocWizard->appendToConfigurationLog( tr("creating folder on ownCloud: %1" ).arg( _remoteFolder ));
|
||||||
connect(ownCloudInfo::instance(), SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
|
ownCloudInfo* info(ownCloudInfo::instance());
|
||||||
|
connect(info, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
|
||||||
this, SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError)));
|
this, SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError)));
|
||||||
|
|
||||||
_mkdirRequestReply = ownCloudInfo::instance()->mkdirRequest( _remoteFolder );
|
_mkdirRequestReply = info->mkdirRequest( _remoteFolder );
|
||||||
|
|
||||||
return (_mkdirRequestReply != NULL);
|
return (_mkdirRequestReply != NULL);
|
||||||
}
|
}
|
||||||
@@ -440,13 +431,118 @@ void OwncloudSetupWizard::finalizeSetup( bool success )
|
|||||||
+ tr("Successfully connected to %1!")
|
+ tr("Successfully connected to %1!")
|
||||||
.arg(Theme::instance()->appNameGUI())
|
.arg(Theme::instance()->appNameGUI())
|
||||||
+ QLatin1String("</b></font></p>"));
|
+ QLatin1String("</b></font></p>"));
|
||||||
|
_ocWizard->successfulStep();
|
||||||
} else {
|
} else {
|
||||||
_ocWizard->appendToConfigurationLog(QLatin1String("<p><font color=\"red\">")
|
_ocWizard->appendToConfigurationLog(QLatin1String("<p><font color=\"red\">")
|
||||||
+ tr("Connection to %1 could not be established. Please check again.")
|
+ tr("Connection to %1 could not be established. Please check again.")
|
||||||
.arg(Theme::instance()->appNameGUI())
|
.arg(Theme::instance()->appNameGUI())
|
||||||
+ QLatin1String("</font></p>"));
|
+ QLatin1String("</font></p>"));
|
||||||
}
|
}
|
||||||
_ocWizard->successfullyConnected(success);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method executed when the user ends the wizard, either with 'accept' or 'reject'.
|
||||||
|
// accept the custom config to be the main one if Accepted.
|
||||||
|
void OwncloudSetupWizard::slotAssistantFinished( int result )
|
||||||
|
{
|
||||||
|
MirallConfigFile cfg( _configHandle );
|
||||||
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
|
|
||||||
|
if( result == QDialog::Rejected ) {
|
||||||
|
// the old config remains valid. Remove the temporary one.
|
||||||
|
cfg.cleanupCustomConfig();
|
||||||
|
qDebug() << "Rejected the new config, use the old!";
|
||||||
|
} else if( result == QDialog::Accepted ) {
|
||||||
|
AbstractCredentials* credentials(_ocWizard->getCredentials());
|
||||||
|
|
||||||
|
qDebug() << "Config Changes were accepted!";
|
||||||
|
|
||||||
|
// go through all folders and remove the journals if the server changed.
|
||||||
|
MirallConfigFile prevCfg;
|
||||||
|
QUrl prevUrl( prevCfg.ownCloudUrl() );
|
||||||
|
QUrl newUrl( cfg.ownCloudUrl() );
|
||||||
|
AbstractCredentials* oldCredentials(prevCfg.getCredentials());
|
||||||
|
|
||||||
|
bool urlHasChanged = (prevUrl.host() != newUrl.host() ||
|
||||||
|
prevUrl.port() != newUrl.port() ||
|
||||||
|
prevUrl.path() != newUrl.path());
|
||||||
|
|
||||||
|
// if the user changed, its also a changed url.
|
||||||
|
if(credentials->changed(oldCredentials)) {
|
||||||
|
urlHasChanged = true;
|
||||||
|
qDebug() << "The User has changed, same as url change.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString localFolder = _ocWizard->localFolder();
|
||||||
|
bool acceptCfg = true;
|
||||||
|
|
||||||
|
if( urlHasChanged ) {
|
||||||
|
// first terminate sync jobs.
|
||||||
|
folderMan->terminateSyncProcess();
|
||||||
|
|
||||||
|
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
||||||
|
if( startFromScratch ) {
|
||||||
|
// first try to rename (backup) the current local dir.
|
||||||
|
bool renameOk = false;
|
||||||
|
while( !renameOk ) {
|
||||||
|
renameOk = folderMan->startFromScratch(localFolder);
|
||||||
|
if( ! renameOk ) {
|
||||||
|
QMessageBox::StandardButton but;
|
||||||
|
but = QMessageBox::question( 0, tr("Folder rename failed"),
|
||||||
|
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
|
||||||
|
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
|
||||||
|
if( but == QMessageBox::Abort ) {
|
||||||
|
renameOk = true;
|
||||||
|
acceptCfg = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now write the resulting folder definition if folder names are set.
|
||||||
|
if( acceptCfg && urlHasChanged ) {
|
||||||
|
folderMan->removeAllFolderDefinitions();
|
||||||
|
folderMan->addFolderDefinition(Theme::instance()->appName(),
|
||||||
|
localFolder, _remoteFolder );
|
||||||
|
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||||
|
} else {
|
||||||
|
// url is unchanged. Only the password was changed.
|
||||||
|
if( acceptCfg ) {
|
||||||
|
qDebug() << "Only password was changed, no changes to folder configuration.";
|
||||||
|
} else {
|
||||||
|
qDebug() << "User interrupted change of configuration.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the user credentials and afterwards clear the cred store.
|
||||||
|
if( acceptCfg ) {
|
||||||
|
cfg.acceptCustomConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the custom config handle
|
||||||
|
_configHandle.clear();
|
||||||
|
ownCloudInfo::instance()->setCustomConfigHandle( QString::null );
|
||||||
|
|
||||||
|
// notify others.
|
||||||
|
emit ownCloudWizardDone( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OwncloudSetupWizard::slotClearPendingRequests()
|
||||||
|
{
|
||||||
|
qDebug() << "Pending request: " << _mkdirRequestReply;
|
||||||
|
if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) {
|
||||||
|
qDebug() << "ABORTing pending mkdir request.";
|
||||||
|
_mkdirRequestReply->abort();
|
||||||
|
}
|
||||||
|
if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) {
|
||||||
|
qDebug() << "ABORTing pending check installation request.";
|
||||||
|
_checkInstallationRequest->abort();
|
||||||
|
}
|
||||||
|
if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) {
|
||||||
|
qDebug() << "ABORTing pending remote folder check request.";
|
||||||
|
_checkRemoteFolderRequest->abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ns Mirall
|
||||||
|
|||||||
@@ -21,81 +21,54 @@
|
|||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
#include "mirall/owncloudwizard.h"
|
|
||||||
#include "mirall/theme.h"
|
#include "mirall/theme.h"
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
class SiteCopyFolder;
|
class OwncloudWizard;
|
||||||
class SyncResult;
|
|
||||||
class ownCloudInfo;
|
|
||||||
class FolderMan;
|
|
||||||
|
|
||||||
class OwncloudSetupWizard : public QObject
|
class OwncloudSetupWizard : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit OwncloudSetupWizard( FolderMan *folderMan = 0, Theme *theme = 0, QObject *parent = 0 );
|
/** Run the wizard */
|
||||||
|
static void runWizard(QObject *obj, const char* amember, QWidget *parent = 0 );
|
||||||
~OwncloudSetupWizard();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @intro wether or not to show the intro wizard page
|
|
||||||
*/
|
|
||||||
void startWizard();
|
|
||||||
|
|
||||||
void installServer();
|
|
||||||
|
|
||||||
bool isBusy();
|
|
||||||
|
|
||||||
void writeOwncloudConfig();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the configured owncloud url if its already configured, otherwise an empty
|
|
||||||
* string.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void setupLocalSyncFolder();
|
|
||||||
|
|
||||||
OwncloudWizard *wizard();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// issued if the oC Setup process (owncloud-admin) is finished.
|
|
||||||
void ownCloudSetupFinished( bool );
|
|
||||||
// overall dialog close signal.
|
// overall dialog close signal.
|
||||||
void ownCloudWizardDone( int );
|
void ownCloudWizardDone( int );
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
// wizard dialog signals
|
|
||||||
void slotConnectToOCUrl( const QString& );
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
|
void slotDetermineAuthType(const QString&);
|
||||||
void slotNoOwnCloudFound( QNetworkReply* );
|
void slotOwnCloudFoundAuth(const QString&, const QString&, const QString&, const QString&);
|
||||||
void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError );
|
void slotAuthCheckReplyFinished();
|
||||||
|
void slotNoOwnCloudFoundAuth(QNetworkReply*);
|
||||||
|
|
||||||
|
void slotConnectToOCUrl(const QString&);
|
||||||
|
void slotConnectionCheck(const QString&, QNetworkReply*);
|
||||||
|
|
||||||
|
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
||||||
|
void slotAuthCheckReply(const QString&, QNetworkReply*);
|
||||||
|
void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError);
|
||||||
void slotAssistantFinished( int );
|
void slotAssistantFinished( int );
|
||||||
void slotClearPendingRequests();
|
void slotClearPendingRequests();
|
||||||
void slotAuthCheckReply( const QString&, QNetworkReply * );
|
|
||||||
private:
|
|
||||||
bool createRemoteFolder();
|
|
||||||
void checkRemoteFolder();
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit OwncloudSetupWizard(QObject *parent = 0 );
|
||||||
|
~OwncloudSetupWizard();
|
||||||
|
|
||||||
|
void startWizard();
|
||||||
|
void testOwnCloudConnect();
|
||||||
|
void checkRemoteFolder(const QString& remoteFolder);
|
||||||
|
bool createRemoteFolder();
|
||||||
void finalizeSetup( bool );
|
void finalizeSetup( bool );
|
||||||
|
|
||||||
/* Start a request to the newly installed ownCloud to check the connection */
|
OwncloudWizard* _ocWizard;
|
||||||
void testOwnCloudConnect();
|
|
||||||
|
|
||||||
OwncloudWizard *_ocWizard;
|
|
||||||
QPointer<QNetworkReply> _mkdirRequestReply;
|
QPointer<QNetworkReply> _mkdirRequestReply;
|
||||||
QPointer<QNetworkReply> _checkInstallationRequest;
|
QPointer<QNetworkReply> _checkInstallationRequest;
|
||||||
QPointer<QNetworkReply> _checkRemoteFolderRequest;
|
QPointer<QNetworkReply> _checkRemoteFolderRequest;
|
||||||
|
QString _configHandle;
|
||||||
FolderMan *_folderMan;
|
QString _remoteFolder;
|
||||||
|
|
||||||
QString _configHandle;
|
|
||||||
QString _remoteFolder;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,32 +52,28 @@ QString ownCloudTheme::about() const
|
|||||||
QString devString;
|
QString devString;
|
||||||
#ifdef GIT_SHA1
|
#ifdef GIT_SHA1
|
||||||
const QString githubPrefix(QLatin1String(
|
const QString githubPrefix(QLatin1String(
|
||||||
" https://github.com/owncloud/mirall/commit/"));
|
"https://github.com/owncloud/mirall/commit/"));
|
||||||
const QString gitSha1(QLatin1String(GIT_SHA1));
|
const QString gitSha1(QLatin1String(GIT_SHA1));
|
||||||
devString = QCoreApplication::translate("ownCloudTheme::about()",
|
devString = QCoreApplication::translate("ownCloudTheme::about()",
|
||||||
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
|
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
|
||||||
" on %3, %4<br>using OCsync %5 and Qt %6.</small><p>")
|
" on %3, %4 using OCsync %5 and Qt %6.</small><p>")
|
||||||
.arg(githubPrefix+gitSha1).arg(gitSha1.left(6))
|
.arg(githubPrefix+gitSha1).arg(gitSha1.left(6))
|
||||||
.arg(__DATE__).arg(__TIME__)
|
.arg(__DATE__).arg(__TIME__)
|
||||||
.arg(MIRALL_STRINGIFY(LIBCSYNC_VERSION))
|
.arg(MIRALL_STRINGIFY(LIBCSYNC_VERSION))
|
||||||
.arg(QT_VERSION_STR);
|
.arg(QT_VERSION_STR);
|
||||||
#endif
|
#endif
|
||||||
return QCoreApplication::translate("ownCloudTheme::about()",
|
return QCoreApplication::translate("ownCloudTheme::about()",
|
||||||
"<p><b>%1 Client Version %2</b></p>"
|
"<p>Version %2. "
|
||||||
"<p><b>Authors</b>"
|
"For more information visit <a href=\"%3\">%4</a></p>"
|
||||||
"<br><a href=\"mailto:freitag@owncloud.com\">"
|
"<p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, ownCloud Inc.<br>"
|
||||||
"Klaas Freitag</a>, ownCloud, Inc."
|
"Based on Mirall by Duncan Mac-Vicar P.</small></p>"
|
||||||
"<br><a href=\"mailto:danimo@owncloud.com\">"
|
|
||||||
"Daniel Molkentin</a>, ownCloud, Inc."
|
|
||||||
"<br><br>Based on Mirall by Duncan Mac-Vicar P.</p>"
|
|
||||||
"<p>For more information visit <a href=\"%3\">%4</a>.</p>"
|
|
||||||
"%7"
|
"%7"
|
||||||
)
|
)
|
||||||
.arg(appName())
|
|
||||||
.arg(MIRALL_STRINGIFY(MIRALL_VERSION))
|
.arg(MIRALL_STRINGIFY(MIRALL_VERSION))
|
||||||
.arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
.arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
||||||
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
||||||
.arg(devString);
|
.arg(devString);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
|
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
|
||||||
@@ -109,6 +105,11 @@ QVariant ownCloudTheme::customMedia(Theme::CustomMediaType type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ownCloudTheme::helpUrl() const
|
||||||
|
{
|
||||||
|
return QString::fromLatin1("http://doc.owncloud.org/desktop/%1.%2/").arg(MIRALL_VERSION_MAJOR).arg(MIRALL_VERSION_MINOR);
|
||||||
|
}
|
||||||
|
|
||||||
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
|
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
|
||||||
{
|
{
|
||||||
return QColor("#1d2d42");
|
return QColor("#1d2d42");
|
||||||
@@ -119,5 +120,12 @@ QColor ownCloudTheme::wizardHeaderTitleColor() const
|
|||||||
return QColor("#ffffff");
|
return QColor("#ffffff");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPixmap ownCloudTheme::wizardHeaderLogo() const
|
||||||
|
{
|
||||||
|
return QPixmap(":/mirall/theme/colored/wizard_logo.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace Mirall {
|
|||||||
|
|
||||||
class ownCloudTheme : public Theme
|
class ownCloudTheme : public Theme
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ownCloudTheme();
|
ownCloudTheme();
|
||||||
|
|
||||||
@@ -35,10 +36,11 @@ public:
|
|||||||
QIcon applicationIcon() const;
|
QIcon applicationIcon() const;
|
||||||
|
|
||||||
QVariant customMedia(CustomMediaType type);
|
QVariant customMedia(CustomMediaType type);
|
||||||
|
QString helpUrl() const;
|
||||||
|
|
||||||
QColor wizardHeaderBackgroundColor() const;
|
QColor wizardHeaderBackgroundColor() const;
|
||||||
QColor wizardHeaderTitleColor() const;
|
QColor wizardHeaderTitleColor() const;
|
||||||
|
QPixmap wizardHeaderLogo() const;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,626 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
|
||||||
* Copyright (C) by Klaas Freitag <freitag@kde.org>
|
|
||||||
*
|
|
||||||
* 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 "mirall/owncloudwizard.h"
|
|
||||||
#include "mirall/mirallconfigfile.h"
|
|
||||||
#include "mirall/theme.h"
|
|
||||||
|
|
||||||
#include "QProgressIndicator.h"
|
|
||||||
|
|
||||||
#include <QtCore>
|
|
||||||
#include <QtGui>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
namespace Mirall
|
|
||||||
{
|
|
||||||
|
|
||||||
void setupCustomMedia( QVariant variant, QLabel *label )
|
|
||||||
{
|
|
||||||
if( !label ) return;
|
|
||||||
|
|
||||||
QPixmap pix = variant.value<QPixmap>();
|
|
||||||
if( !pix.isNull() ) {
|
|
||||||
label->setPixmap(pix);
|
|
||||||
label->setAlignment( Qt::AlignTop | Qt::AlignRight );
|
|
||||||
label->setVisible(true);
|
|
||||||
} else {
|
|
||||||
QString str = variant.toString();
|
|
||||||
if( !str.isEmpty() ) {
|
|
||||||
label->setText( str );
|
|
||||||
label->setTextFormat( Qt::RichText );
|
|
||||||
label->setVisible(true);
|
|
||||||
label->setOpenExternalLinks(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================================================================
|
|
||||||
|
|
||||||
OwncloudSetupPage::OwncloudSetupPage()
|
|
||||||
{
|
|
||||||
_ui.setupUi(this);
|
|
||||||
|
|
||||||
Theme *theme = Theme::instance();
|
|
||||||
setTitle( tr("<font color=\"%1\" size=\"5\">Connect to %2</font>")
|
|
||||||
.arg(theme->wizardHeaderTitleColor().name()).arg( theme->appNameGUI()));
|
|
||||||
setSubTitle( tr("<font color=\"%1\">Enter user credentials</font>")
|
|
||||||
.arg(theme->wizardHeaderTitleColor().name()));
|
|
||||||
|
|
||||||
registerField( QLatin1String("OCUrl"), _ui.leUrl );
|
|
||||||
registerField( QLatin1String("OCUser"), _ui.leUsername );
|
|
||||||
registerField( QLatin1String("OCPasswd"), _ui.lePassword);
|
|
||||||
registerField( QLatin1String("OCSyncFromScratch"), _ui.cbSyncFromScratch);
|
|
||||||
|
|
||||||
_ui.errorLabel->setVisible(true);
|
|
||||||
_ui.advancedBox->setVisible(false);
|
|
||||||
|
|
||||||
_progressIndi = new QProgressIndicator;
|
|
||||||
_ui.resultLayout->addWidget( _progressIndi );
|
|
||||||
_progressIndi->setVisible(false);
|
|
||||||
_ui.resultLayout->setEnabled(false);
|
|
||||||
|
|
||||||
// Error label
|
|
||||||
QString style = QLatin1String("border: 1px solid #eed3d7; border-radius: 5px; padding: 3px;"
|
|
||||||
"background-color: #f2dede; color: #b94a48;");
|
|
||||||
|
|
||||||
|
|
||||||
_ui.errorLabel->setStyleSheet( style );
|
|
||||||
_ui.errorLabel->setWordWrap(true);
|
|
||||||
_ui.errorLabel->setVisible(false);
|
|
||||||
|
|
||||||
_checking = false;
|
|
||||||
|
|
||||||
setupCustomization();
|
|
||||||
|
|
||||||
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
|
|
||||||
connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SLOT(slotUserChanged(QString)));
|
|
||||||
|
|
||||||
connect( _ui.lePassword, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged()));
|
|
||||||
connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged()));
|
|
||||||
connect( _ui.cbAdvanced, SIGNAL(stateChanged (int)), SLOT(slotToggleAdvanced(int)));
|
|
||||||
connect( _ui.pbSelectLocalFolder, SIGNAL(clicked()), SLOT(slotSelectFolder()));
|
|
||||||
}
|
|
||||||
|
|
||||||
OwncloudSetupPage::~OwncloudSetupPage()
|
|
||||||
{
|
|
||||||
delete _progressIndi;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::slotToggleAdvanced(int state)
|
|
||||||
{
|
|
||||||
_ui.advancedBox->setVisible( state == Qt::Checked );
|
|
||||||
slotHandleUserInput();
|
|
||||||
QSize size = wizard()->sizeHint();
|
|
||||||
// need to substract header for some reason
|
|
||||||
size -= QSize(0, 63);
|
|
||||||
|
|
||||||
wizard()->setMinimumSize(size);
|
|
||||||
wizard()->resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setOCUser( const QString & user )
|
|
||||||
{
|
|
||||||
_ocUser = user;
|
|
||||||
_ui.leUsername->setText(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
|
|
||||||
{
|
|
||||||
_oCUrl = newUrl;
|
|
||||||
if( _oCUrl.isEmpty() ) {
|
|
||||||
_ui.leUrl->clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ui.leUrl->setText( _oCUrl );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setupCustomization()
|
|
||||||
{
|
|
||||||
// set defaults for the customize labels.
|
|
||||||
_ui.topLabel->hide();
|
|
||||||
_ui.bottomLabel->hide();
|
|
||||||
|
|
||||||
Theme *theme = Theme::instance();
|
|
||||||
QVariant variant = theme->customMedia( Theme::oCSetupTop );
|
|
||||||
if( !variant.isNull() ) {
|
|
||||||
setupCustomMedia( variant, _ui.topLabel );
|
|
||||||
}
|
|
||||||
|
|
||||||
variant = theme->customMedia( Theme::oCSetupBottom );
|
|
||||||
setupCustomMedia( variant, _ui.bottomLabel );
|
|
||||||
|
|
||||||
QString fixUrl = theme->overrideServerUrl();
|
|
||||||
if( !fixUrl.isEmpty() ) {
|
|
||||||
_ui.label_2->hide();
|
|
||||||
setServerUrl( fixUrl );
|
|
||||||
_ui.leUrl->setEnabled( false );
|
|
||||||
_ui.leUrl->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::slotUserChanged(const QString& user )
|
|
||||||
{
|
|
||||||
slotHandleUserInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// slot hit from textChanged of the url entry field.
|
|
||||||
void OwncloudSetupPage::slotUrlChanged(const QString& ocUrl)
|
|
||||||
{
|
|
||||||
slotHandleUserInput();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
QString url = ocUrl;
|
|
||||||
bool visible = false;
|
|
||||||
|
|
||||||
if (url.startsWith(QLatin1String("https://"))) {
|
|
||||||
_ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-high.png"));
|
|
||||||
_ui.urlLabel->setToolTip(tr("This url is secure. You can use it."));
|
|
||||||
visible = true;
|
|
||||||
}
|
|
||||||
if (url.startsWith(QLatin1String("http://"))) {
|
|
||||||
_ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-low.png"));
|
|
||||||
_ui.urlLabel->setToolTip(tr("This url is NOT secure. You should not use it."));
|
|
||||||
visible = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudSetupPage::isComplete() const
|
|
||||||
{
|
|
||||||
if( _ui.leUrl->text().isEmpty() ) return false;
|
|
||||||
if( _checking ) return false;
|
|
||||||
|
|
||||||
return !( _ui.lePassword->text().isEmpty() || _ui.leUsername->text().isEmpty() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::initializePage()
|
|
||||||
{
|
|
||||||
_connected = false;
|
|
||||||
_checking = false;
|
|
||||||
_multipleFoldersExist = false;
|
|
||||||
|
|
||||||
// call to init label
|
|
||||||
slotHandleUserInput();
|
|
||||||
|
|
||||||
if( _configExists ) {
|
|
||||||
_ui.lePassword->setFocus();
|
|
||||||
} else {
|
|
||||||
_ui.leUrl->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudSetupPage::urlHasChanged()
|
|
||||||
{
|
|
||||||
bool change = false;
|
|
||||||
const QChar slash('/');
|
|
||||||
|
|
||||||
QUrl currentUrl( url() );
|
|
||||||
QUrl initialUrl( _oCUrl );
|
|
||||||
|
|
||||||
QString currentPath = currentUrl.path();
|
|
||||||
QString initialPath = initialUrl.path();
|
|
||||||
|
|
||||||
// add a trailing slash.
|
|
||||||
if( ! currentPath.endsWith( slash )) currentPath += slash;
|
|
||||||
if( ! initialPath.endsWith( slash )) initialPath += slash;
|
|
||||||
|
|
||||||
if( currentUrl.host() != initialUrl.host() ||
|
|
||||||
currentPath != initialPath ) {
|
|
||||||
change = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !change) { // no change yet, check the user.
|
|
||||||
QString user = _ui.leUsername->text().simplified();
|
|
||||||
if( user != _ocUser ) change = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return change;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called if the user changes the user- or url field. Adjust the texts and
|
|
||||||
// evtl. warnings on the dialog.
|
|
||||||
void OwncloudSetupPage::slotHandleUserInput()
|
|
||||||
{
|
|
||||||
// if the url has not changed, return.
|
|
||||||
if( ! urlHasChanged() ) {
|
|
||||||
// disable the advanced button as nothing has changed.
|
|
||||||
_ui.cbAdvanced->setEnabled(false);
|
|
||||||
_ui.advancedBox->setEnabled(false);
|
|
||||||
} else {
|
|
||||||
// Enable advanced stuff for new connection configuration.
|
|
||||||
_ui.cbAdvanced->setEnabled(true);
|
|
||||||
_ui.advancedBox->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString locFolder = localFolder();
|
|
||||||
|
|
||||||
// check if the local folder exists. If so, and if its not empty, show a warning.
|
|
||||||
QDir dir( locFolder );
|
|
||||||
QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
|
|
||||||
|
|
||||||
QString t;
|
|
||||||
|
|
||||||
if( !urlHasChanged() && _configExists ) {
|
|
||||||
// This is the password change mode: No change to the url and a config
|
|
||||||
// to an ownCloud exists.
|
|
||||||
t = tr("Change the Password for your configured account.");
|
|
||||||
} else {
|
|
||||||
// Complete new setup.
|
|
||||||
_ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder));
|
|
||||||
|
|
||||||
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
|
|
||||||
t = tr("Your entire account will be synced to the local folder '%1'.")
|
|
||||||
.arg(QDir::toNativeSeparators(locFolder));
|
|
||||||
} else {
|
|
||||||
t = tr("%1 folder '%2' is synced to local folder '%3'")
|
|
||||||
.arg(Theme::instance()->appName()).arg(_remoteFolder)
|
|
||||||
.arg(QDir::toNativeSeparators(locFolder));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _multipleFoldersExist ) {
|
|
||||||
t += tr("<p><small><strong>Warning:</strong> You currently have multiple folders "
|
|
||||||
"configured. If you continue with the current settings, the folder configurations "
|
|
||||||
"will be discarded and a single root folder sync will be created!</small></p>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( entries.count() > 0) {
|
|
||||||
// the directory is not empty
|
|
||||||
if (!_ui.cbAdvanced->isChecked()) {
|
|
||||||
t += tr("<p><small><strong>Warning:</strong> The local directory is not empty. "
|
|
||||||
"Pick a resolution in the advanced settings!</small></p>");
|
|
||||||
}
|
|
||||||
_ui.resolutionWidget->setVisible(true);
|
|
||||||
} else {
|
|
||||||
// the dir is empty, which means that there is no problem.
|
|
||||||
_ui.resolutionWidget->setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ui.syncModeLabel->setText(t);
|
|
||||||
_ui.syncModeLabel->setFixedHeight(_ui.syncModeLabel->sizeHint().height());
|
|
||||||
}
|
|
||||||
|
|
||||||
int OwncloudSetupPage::nextId() const
|
|
||||||
{
|
|
||||||
return OwncloudWizard::Page_Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OwncloudSetupPage::url() const
|
|
||||||
{
|
|
||||||
QString url = _ui.leUrl->text().simplified();
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OwncloudSetupPage::localFolder() const
|
|
||||||
{
|
|
||||||
QString folder = wizard()->property("localFolder").toString();
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setConnected( bool comp )
|
|
||||||
{
|
|
||||||
_connected = comp;
|
|
||||||
_ui.resultLayout->setEnabled(true);
|
|
||||||
_progressIndi->setVisible(false);
|
|
||||||
_progressIndi->stopAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudSetupPage::validatePage()
|
|
||||||
{
|
|
||||||
bool re = false;
|
|
||||||
|
|
||||||
if( ! _connected) {
|
|
||||||
setErrorString(QString::null);
|
|
||||||
_checking = true;
|
|
||||||
_ui.resultLayout->setEnabled(true);
|
|
||||||
_progressIndi->setVisible(true);
|
|
||||||
_progressIndi->startAnimation();
|
|
||||||
emit completeChanged();
|
|
||||||
|
|
||||||
emit connectToOCUrl( url() );
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// connecting is running
|
|
||||||
stopSpinner();
|
|
||||||
_checking = false;
|
|
||||||
emit completeChanged();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setErrorString( const QString& err )
|
|
||||||
{
|
|
||||||
if( err.isEmpty()) {
|
|
||||||
_ui.errorLabel->setVisible(false);
|
|
||||||
} else {
|
|
||||||
_ui.errorLabel->setVisible(true);
|
|
||||||
_ui.errorLabel->setText(err);
|
|
||||||
}
|
|
||||||
_checking = false;
|
|
||||||
emit completeChanged();
|
|
||||||
stopSpinner();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::stopSpinner()
|
|
||||||
{
|
|
||||||
_ui.resultLayout->setEnabled(false);
|
|
||||||
_progressIndi->setVisible(false);
|
|
||||||
_progressIndi->stopAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
OwncloudSetupPage::SyncMode OwncloudSetupPage::syncMode()
|
|
||||||
{
|
|
||||||
return BoxMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setRemoteFolder( const QString& remoteFolder )
|
|
||||||
{
|
|
||||||
if( !remoteFolder.isEmpty() ) {
|
|
||||||
_remoteFolder = remoteFolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setMultipleFoldersExist(bool exist)
|
|
||||||
{
|
|
||||||
_multipleFoldersExist = exist;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::slotSelectFolder()
|
|
||||||
{
|
|
||||||
|
|
||||||
QString dir = QFileDialog::getExistingDirectory(0, tr("Local Sync Folder"), QDir::homePath());
|
|
||||||
if( !dir.isEmpty() ) {
|
|
||||||
_ui.pbSelectLocalFolder->setText(dir);
|
|
||||||
wizard()->setProperty("localFolder", dir);
|
|
||||||
slotHandleUserInput();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OwncloudSetupPage::SyncMode OwncloudWizard::syncMode()
|
|
||||||
{
|
|
||||||
return _setupPage->syncMode();
|
|
||||||
return OwncloudSetupPage::BoxMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::setMultipleFoldersExist(bool exist)
|
|
||||||
{
|
|
||||||
_setupPage->setMultipleFoldersExist(exist);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupPage::setConfigExists( bool config )
|
|
||||||
{
|
|
||||||
_configExists = config;
|
|
||||||
|
|
||||||
if (config == true) {
|
|
||||||
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
|
|
||||||
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================================================================
|
|
||||||
|
|
||||||
OwncloudWizardResultPage::OwncloudWizardResultPage()
|
|
||||||
{
|
|
||||||
_ui.setupUi(this);
|
|
||||||
// no fields to register.
|
|
||||||
|
|
||||||
Theme *theme = Theme::instance();
|
|
||||||
setTitle( tr("<font color=\"%1\" size=\"5\">Everything set up!</font>")
|
|
||||||
.arg(theme->wizardHeaderTitleColor().name()));
|
|
||||||
// required to show header in QWizard's modern style
|
|
||||||
setSubTitle( QLatin1String(" ") );
|
|
||||||
|
|
||||||
_ui.pbOpenLocal->setText("Open local folder");
|
|
||||||
_ui.pbOpenServer->setText(tr("Open %1").arg(Theme::instance()->appNameGUI()));
|
|
||||||
|
|
||||||
_ui.pbOpenLocal->setIcon(QIcon(":/mirall/resources/folder-sync.png"));
|
|
||||||
_ui.pbOpenLocal->setText(tr("Open Local Folder"));
|
|
||||||
_ui.pbOpenLocal->setIconSize(QSize(48, 48));
|
|
||||||
connect(_ui.pbOpenLocal, SIGNAL(clicked()), SLOT(slotOpenLocal()));
|
|
||||||
|
|
||||||
_ui.pbOpenLocal->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
||||||
|
|
||||||
QIcon appIcon = theme->applicationIcon();
|
|
||||||
_ui.pbOpenServer->setIcon(appIcon.pixmap(48));
|
|
||||||
_ui.pbOpenServer->setText(tr("Open %1").arg(theme->appNameGUI()));
|
|
||||||
_ui.pbOpenServer->setIconSize(QSize(48, 48));
|
|
||||||
_ui.pbOpenServer->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
||||||
connect(_ui.pbOpenServer, SIGNAL(clicked()), SLOT(slotOpenServer()));
|
|
||||||
setupCustomization();
|
|
||||||
}
|
|
||||||
|
|
||||||
OwncloudWizardResultPage::~OwncloudWizardResultPage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::setComplete(bool complete)
|
|
||||||
{
|
|
||||||
_complete = complete;
|
|
||||||
emit completeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudWizardResultPage::isComplete() const
|
|
||||||
{
|
|
||||||
return _complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::initializePage()
|
|
||||||
{
|
|
||||||
const QString localFolder = wizard()->property("localFolder").toString();
|
|
||||||
QString text;
|
|
||||||
if( _remoteFolder == QLatin1String("/") || _remoteFolder.isEmpty() ) {
|
|
||||||
text = tr("Your entire account is synced to the local folder <i>%1</i>")
|
|
||||||
.arg(QDir::toNativeSeparators(localFolder));
|
|
||||||
} else {
|
|
||||||
text = tr("ownCloud folder <i>%1</i> is synced to local folder <i>%2</i>")
|
|
||||||
.arg(_remoteFolder).arg(QDir::toNativeSeparators(localFolder));
|
|
||||||
}
|
|
||||||
_ui.localFolderLabel->setText( text );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::setRemoteFolder(const QString &remoteFolder)
|
|
||||||
{
|
|
||||||
_remoteFolder = remoteFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::setupCustomization()
|
|
||||||
{
|
|
||||||
// set defaults for the customize labels.
|
|
||||||
_ui.topLabel->setText( QString::null );
|
|
||||||
_ui.topLabel->hide();
|
|
||||||
|
|
||||||
QVariant variant = Theme::instance()->customMedia( Theme::oCSetupResultTop );
|
|
||||||
setupCustomMedia( variant, _ui.topLabel );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Folder wizard itself
|
|
||||||
*/
|
|
||||||
|
|
||||||
OwncloudWizard::OwncloudWizard(QWidget *parent)
|
|
||||||
: QWizard(parent),
|
|
||||||
_configExists(false)
|
|
||||||
{
|
|
||||||
_setupPage = new OwncloudSetupPage;
|
|
||||||
_resultPage = new OwncloudWizardResultPage;
|
|
||||||
setPage(Page_oCSetup, _setupPage );
|
|
||||||
setPage(Page_Result, _resultPage );
|
|
||||||
|
|
||||||
// note: start Id is set by the calling class depending on if the
|
|
||||||
// welcome text is to be shown or not.
|
|
||||||
setWizardStyle( QWizard::ModernStyle );
|
|
||||||
|
|
||||||
connect( this, SIGNAL(currentIdChanged(int)), SLOT(slotCurrentPageChanged(int)));
|
|
||||||
|
|
||||||
connect( _setupPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString)));
|
|
||||||
|
|
||||||
|
|
||||||
Theme *theme = Theme::instance();
|
|
||||||
setWizardStyle(QWizard::ModernStyle);
|
|
||||||
setPixmap( QWizard::BannerPixmap, theme->wizardHeaderBanner() );
|
|
||||||
setPixmap( QWizard::LogoPixmap, theme->wizardHeaderLogo() );
|
|
||||||
setOption( QWizard::NoBackButtonOnStartPage );
|
|
||||||
setOption( QWizard::NoBackButtonOnLastPage );
|
|
||||||
setOption( QWizard::NoCancelButton );
|
|
||||||
setTitleFormat(Qt::RichText);
|
|
||||||
setSubTitleFormat(Qt::RichText);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OwncloudWizard::localFolder() const
|
|
||||||
{
|
|
||||||
return(_setupPage->localFolder());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OwncloudWizard::ocUrl() const
|
|
||||||
{
|
|
||||||
QString url = field("OCUrl").toString().simplified();
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::enableFinishOnResultWidget(bool enable)
|
|
||||||
{
|
|
||||||
_resultPage->setComplete(enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::setRemoteFolder( const QString& remoteFolder )
|
|
||||||
{
|
|
||||||
_setupPage->setRemoteFolder( remoteFolder );
|
|
||||||
_resultPage->setRemoteFolder( remoteFolder );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::showConnectInfo( const QString& msg )
|
|
||||||
{
|
|
||||||
if( _setupPage ) {
|
|
||||||
_setupPage->setErrorString( msg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::successfullyConnected(bool enable)
|
|
||||||
{
|
|
||||||
_setupPage->setConnected( enable );
|
|
||||||
|
|
||||||
if( enable ) {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::slotCurrentPageChanged( int id )
|
|
||||||
{
|
|
||||||
qDebug() << "Current Wizard page changed to " << id;
|
|
||||||
|
|
||||||
if( id == Page_oCSetup ) {
|
|
||||||
setButtonText( QWizard::NextButton, tr("Connect...") );
|
|
||||||
emit clearPendingRequests();
|
|
||||||
_setupPage->initializePage();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if( id == Page_Result ) {
|
|
||||||
appendToConfigurationLog( QString::null );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::displayError( const QString& msg )
|
|
||||||
{
|
|
||||||
_setupPage->setErrorString( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::appendToConfigurationLog( const QString& msg, LogType type )
|
|
||||||
{
|
|
||||||
_setupLog << msg;
|
|
||||||
qDebug() << "Setup-Log: " << msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::setOCUrl( const QString& url )
|
|
||||||
{
|
|
||||||
_setupPage->setServerUrl( url );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::setOCUser( const QString& user )
|
|
||||||
{
|
|
||||||
_oCUser = user;
|
|
||||||
_setupPage->setOCUser( user );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizard::setConfigExists( bool config )
|
|
||||||
{
|
|
||||||
_configExists = config;
|
|
||||||
_setupPage->setConfigExists( config );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudWizard::configExists()
|
|
||||||
{
|
|
||||||
return _configExists;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::slotOpenLocal()
|
|
||||||
{
|
|
||||||
const QString localFolder = wizard()->property("localFolder").toString();
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(localFolder));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudWizardResultPage::slotOpenServer()
|
|
||||||
{
|
|
||||||
QUrl url = field("OCUrl").toUrl();
|
|
||||||
qDebug() << Q_FUNC_INFO << url;
|
|
||||||
QDesktopServices::openUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // end namespace
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user