mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-05 05:34:18 +02:00
Compare commits
210 Commits
v1.6.0-bet
...
v1.6.1-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a8a3855b8 | ||
|
|
603a238eb9 | ||
|
|
b7b6cf4b3f | ||
|
|
c855b783d9 | ||
|
|
f593fc8e4d | ||
|
|
ae5cbb8451 | ||
|
|
041066a252 | ||
|
|
9ca82ba14d | ||
|
|
b29a757b18 | ||
|
|
485a6926c5 | ||
|
|
f3de6f46db | ||
|
|
1309dc27d9 | ||
|
|
31469d6a3e | ||
|
|
88776770f7 | ||
|
|
bbf8b9f8dd | ||
|
|
6ff38d8005 | ||
|
|
6d13b5cc43 | ||
|
|
73ab2804c4 | ||
|
|
db3d2eed5f | ||
|
|
d995d1190f | ||
|
|
3217e42a0f | ||
|
|
1dd58a537e | ||
|
|
b34afa1afc | ||
|
|
b7c9fa6d5f | ||
|
|
61ad376bf4 | ||
|
|
407b3bebfe | ||
|
|
f04c80dd0e | ||
|
|
1e788d3d60 | ||
|
|
83171bf025 | ||
|
|
2e51721851 | ||
|
|
4d4a0148e4 | ||
|
|
b144a5bbf9 | ||
|
|
5225fe07e0 | ||
|
|
85cdbd1f1d | ||
|
|
e4f8a136f1 | ||
|
|
c263c38cdf | ||
|
|
df8553e878 | ||
|
|
bec66c85d4 | ||
|
|
f9710cc1d5 | ||
|
|
6b041b0846 | ||
|
|
d0c992c991 | ||
|
|
9ee86cf06b | ||
|
|
646eafb05d | ||
|
|
0880444e37 | ||
|
|
0a953b91f9 | ||
|
|
b71881d300 | ||
|
|
b91967f4d9 | ||
|
|
2d234cd96f | ||
|
|
1230e87330 | ||
|
|
b2966fecc7 | ||
|
|
4abe00ff6c | ||
|
|
e1db834ec9 | ||
|
|
c72c72a106 | ||
|
|
4a5ef8f173 | ||
|
|
ed26bcb3e7 | ||
|
|
b814b45e50 | ||
|
|
ded8914df2 | ||
|
|
7a7b0e8939 | ||
|
|
a4f6370774 | ||
|
|
6605a89990 | ||
|
|
6e10b8c5c4 | ||
|
|
24616bead4 | ||
|
|
13f9970257 | ||
|
|
746c15b4aa | ||
|
|
7e65c9741e | ||
|
|
a50e7c1b48 | ||
|
|
0ae82e2041 | ||
|
|
22af756fe3 | ||
|
|
2f1bec28dd | ||
|
|
022a3fcd92 | ||
|
|
064dcdb25a | ||
|
|
938dce7fa6 | ||
|
|
0151682a53 | ||
|
|
864f2cdc7d | ||
|
|
77ddedc859 | ||
|
|
0c1ab533e6 | ||
|
|
1dd7f736d0 | ||
|
|
571c199db8 | ||
|
|
40715cbc77 | ||
|
|
3d2a2df86f | ||
|
|
86a48b52e9 | ||
|
|
ebe1f986f1 | ||
|
|
dd1152dd4f | ||
|
|
ce9bfd319a | ||
|
|
f591ac6549 | ||
|
|
4fd368c992 | ||
|
|
93f453057b | ||
|
|
5a069d274b | ||
|
|
e275ad3866 | ||
|
|
5813f63df8 | ||
|
|
9a1f8ccf7b | ||
|
|
449c00f019 | ||
|
|
6017eb7ca6 | ||
|
|
f1b2417967 | ||
|
|
181383e5f1 | ||
|
|
c1b9d5c653 | ||
|
|
964c3ac7bf | ||
|
|
6d8afabf41 | ||
|
|
0a7dbeb778 | ||
|
|
3228fde4af | ||
|
|
0582abe8dd | ||
|
|
81f410970f | ||
|
|
e75c5236f2 | ||
|
|
8a671c40d1 | ||
|
|
50ce0f9681 | ||
|
|
a60902b33d | ||
|
|
5220786cf2 | ||
|
|
99cead68f5 | ||
|
|
7a209ba376 | ||
|
|
f9263da3de | ||
|
|
3f724e1c6a | ||
|
|
c9d3f7a0eb | ||
|
|
072af16f3b | ||
|
|
d2b6c626b5 | ||
|
|
115276408a | ||
|
|
9abffdb1a6 | ||
|
|
5b0307446a | ||
|
|
0f20a4f546 | ||
|
|
1b2875c20a | ||
|
|
bbdf7bf955 | ||
|
|
57359968ed | ||
|
|
ea9f302b7a | ||
|
|
ef0a3c212e | ||
|
|
18677dbc3f | ||
|
|
7e8b403116 | ||
|
|
1303379c9e | ||
|
|
b995cd318c | ||
|
|
ed19107161 | ||
|
|
1b67f253dc | ||
|
|
667c835c49 | ||
|
|
5b298abba1 | ||
|
|
4edbeece49 | ||
|
|
97362cff32 | ||
|
|
3db3c7b876 | ||
|
|
8738128504 | ||
|
|
069eaf9170 | ||
|
|
d0b9b002e4 | ||
|
|
bdba56f60b | ||
|
|
7087dbc445 | ||
|
|
7ade4bb6e6 | ||
|
|
86117aed0d | ||
|
|
ed3d9a7479 | ||
|
|
3746a2efff | ||
|
|
9b53cc66e7 | ||
|
|
43fe7b0d55 | ||
|
|
5aa6f81ef3 | ||
|
|
f838f28185 | ||
|
|
e1f8eb5aa5 | ||
|
|
f40a054cb7 | ||
|
|
adfb163593 | ||
|
|
81c768099e | ||
|
|
4bcaebb322 | ||
|
|
8b469d3992 | ||
|
|
bb929db7e6 | ||
|
|
90ee274744 | ||
|
|
9f6e9f8e1b | ||
|
|
943f9f60e3 | ||
|
|
f89bfce068 | ||
|
|
ef44a59bed | ||
|
|
d96139f698 | ||
|
|
de970eb0a5 | ||
|
|
7a28b44128 | ||
|
|
17a2e224c4 | ||
|
|
87386ce001 | ||
|
|
5ed4710d64 | ||
|
|
5493c22584 | ||
|
|
64f4d1b387 | ||
|
|
cdd8c8165b | ||
|
|
16ffd7fbe4 | ||
|
|
ba959f7cf9 | ||
|
|
cf145feed8 | ||
|
|
07f57b1982 | ||
|
|
e62eb62a01 | ||
|
|
574e030caf | ||
|
|
3705a42375 | ||
|
|
a9ffd1d0cf | ||
|
|
f86dd1cbbf | ||
|
|
af066cc733 | ||
|
|
822650719b | ||
|
|
95747fbaea | ||
|
|
321058ef74 | ||
|
|
71c11373d8 | ||
|
|
d5ba288dd5 | ||
|
|
091e9bbd52 | ||
|
|
ce09e11011 | ||
|
|
d7a226e0e6 | ||
|
|
f034bcb9ae | ||
|
|
4c77a04514 | ||
|
|
a50c39cd0c | ||
|
|
370dd99e47 | ||
|
|
f97fbe868f | ||
|
|
2ce6560b6e | ||
|
|
2b4e14c4fc | ||
|
|
1631cfdaf1 | ||
|
|
2e76fe87c2 | ||
|
|
6c44f53645 | ||
|
|
988c162d2f | ||
|
|
3d8d4fecd7 | ||
|
|
f8525fa5a0 | ||
|
|
6e48eb9397 | ||
|
|
88cb047197 | ||
|
|
7f7154ed40 | ||
|
|
a8c1ffc2f4 | ||
|
|
df8b5b1ea6 | ||
|
|
ce50cdecf1 | ||
|
|
77c7439329 | ||
|
|
752112dbaa | ||
|
|
925c6485e6 | ||
|
|
738f026c41 | ||
|
|
32e205f6ce |
11
ChangeLog
11
ChangeLog
@@ -1,18 +1,22 @@
|
||||
ChangeLog
|
||||
=========
|
||||
version 1.6.0 (release 2014-04- )
|
||||
version 1.6.0 (release 2014-05-30 )
|
||||
* Minor GUI improvements
|
||||
* Qt5 compile issues fixed
|
||||
* Ignore sync log file in filewatcher
|
||||
* Install libocsync to private library dir and use rpath to localize
|
||||
* Fix reconnect after server disconnect
|
||||
* Fix crashes
|
||||
* Fix "unknown action" display in Activity window
|
||||
* Fix memory leaks
|
||||
* Respect XDG_CONFIG_HOME environment var
|
||||
* Handle empty fileids in the journal correctly
|
||||
* Add abilility to compile libowncloudsync without GUI dependendy
|
||||
|
||||
* Fix SSL error with previously-expired CAs on Windows
|
||||
* Fix incorrect folder pause state after start
|
||||
* Fix a couple of actual potential crashes
|
||||
* Improve Cookie support (e.g. for cookie-based load-balancers)
|
||||
* Introduce a general timeout of 300s for network operations
|
||||
* Improve error handling, blacklisting
|
||||
* Job-based change propagation, enables faster parallel up/downloads
|
||||
(right now only if no bandwidth limit is set and no proxy is used)
|
||||
* Significantly reduced CPU load when checking for local and remote changes
|
||||
@@ -30,6 +34,7 @@ version 1.6.0 (release 2014-04- )
|
||||
* Mac OS X: Fix UI inconsistencies on Mavericks
|
||||
* Shibboleth: Warn if authenticating with a different user
|
||||
* Remove vio abstraction in csync
|
||||
* Avoid data loss when a client file system is not case sensitive
|
||||
|
||||
version 1.5.3 (release 2014-03-10 )
|
||||
* Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
set( MIRALL_VERSION_MAJOR 1 )
|
||||
set( MIRALL_VERSION_MINOR 6 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_PATCH 1 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "beta2" ) #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "rc1") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
@@ -3,13 +3,13 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Βρέθηκε η(οι) διεργασία(ες) ${APPLICATION_EXECUTABLE} η(οι) οποία(ες) θα πρέπει να τερματιστεί(ούν).$\nΘα θέλατε να την(τις) τερματίσει ο βοηθός εγκατάστασης για εσάς;"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Τερματισμός διεργασιών ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Δεν βρέθηκε διεργασία για βίαιο τερματισμό!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Μια παλαιότερη έκδοση της ${APPLICATION_NAME} είναι εγκατεστημένη στο σύστημά σας. Είναι προτεινόμενο να απεγκαταστήσετε την τρέχουσα έκδοση πριν την εγκατάσταση. Επιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και πατήστε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Μια παλαιότερη έκδοση της ${APPLICATION_NAME} είναι εγκατεστημένη στο σύστημά σας. Είναι προτεινόμενο να απεγκαταστήσετε την τρέχουσα έκδοση πριν την εγκατάσταση. Επιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και πατήστε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Απεγκατάσταση πριν την εγκατάσταση"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Να μην απεγκατασταθεί"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ήδη εγκατεστημένο"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ήδη εγκατεστημένη"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Επιλέξτε πώς θέλετε να εγκαταστήσετε την ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Μια νεώτερη έκδοση της ${APPLICATION_NAME} είναι ήδη εγκατεστημένη! Δεν συνίσταται να εγκαταστείσετε μια παλαιότερη έκδοση. Εάν θέλετε πραγματικά να εγκαταστήσετε αυτή την παλαιότερη έκδοση, είναι καλύτερο να απεγκαταστήσετε την τρέχουσα έκδοση πρώτα. Επιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και επιλέξτε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "Η ${APPLICATION_NAME} ${VERSION} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και επιλέξτε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Μια νεώτερη έκδοση της ${APPLICATION_NAME} είναι ήδη εγκατεστημένη! Δεν συνίσταται να εγκαταστείσετε μια παλαιότερη έκδοση. Εάν θέλετε πραγματικά να εγκαταστήσετε αυτήν την παλαιότερη έκδοση, είναι καλύτερο να απεγκαταστήσετε την τρέχουσα έκδοση πρώτα. Επιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "Η ${APPLICATION_NAME} ${VERSION} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Προσθήκη/ Επανεγκατάσταση συνιστωσών"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Απεγκατάσταση ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Απεγκατάσταση ${APPLICATION_NAME}"
|
||||
@@ -23,16 +23,16 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Δημιουργία Συντόμευσης Ταχείας Εκκίνησης"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "Βάση ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Συντόμευση ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Συντόμευση στην επιφάνεια εργασίας της "
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Συντόμευση Ταχείας Εκκίνησης της "
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Αφαίρεση του φακέλου δεδομένων της ${APPLICATION_NAME} από τον υπολογιστή σας"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Συντόμευση επιφάνειας εργασίας της ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Συντόμευση Ταχείας Εκκίνησης της ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Αφαίρεση του φακέλου δεδομένων της ${APPLICATION_NAME} από τον υπολογιστή σας."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Θέλετε να αφαιρέσετε τον φάκελο δεδομένων της ${APPLICATION_NAME};"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Αφήστε κενό για να διατηρήσετε τον φάκελο δεδομένων για μελλοντική χρήση ή επιλέξτε για να διγράψετε το φάκελο δεδομένων."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Να διαγραφεί ο φάκελος δεδομένων."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Ναι, διαγραφή αυτού του φακέλου δεδομένων."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Εγγραφή Εφαρμογής Απεγκατάστασης"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Εγγραφή Κλειδιών μητρώου (Registry) της Εφαρμογής Εγκατάστασης"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκλήρωση"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Φαίνεται πως η ${APPLICATION_NAME} είναι εγκατεστημένη στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκληρώθηκε"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Δεν φαίνεται να είναι εγκατεστημένηη η ${APPLICATION_NAME} στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);"
|
||||
StrCpy $UNINSTALL_ABORT "Η απεγκατάσταση ματαιώθηκε από το χρήστη"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Συντόμευση Ταχείας Εκκίνησης (Μ/Δ)"
|
||||
StrCpy $INIT_NO_DESKTOP "Συντόμευση Επιφάνειας Εργασίας (αντικαθιστά υπάρχουσα)"
|
||||
|
||||
@@ -9,7 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Kald
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Zaten Yüklü"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} uygulamasını nasıl yüklemek istediğinizi seçin."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} uygulamasının daha yeni sürümü zaten yüklü! Daha eski bir sürümünü yüklemeniz önerilmez. Gerçekten bu eski sürümü yüklemek isterseniz, ilk olarak geçerli sürümü kaldırmanız tavsiye edilir. Yapmak istediğiniz işlemi seçin ve devam etmek üzere İleri tıklayın."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} zaten yüklü.\nYapmak istediğiniz işlemi seçin ve devam etmek için İleri tıklayın."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} zaten yüklü.\n\nYapmak istediğiniz işlemi seçin ve devam etmek için İleri tıklayın."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Bileşenleri ekle/yeniden yükle"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamasını kaldır"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasını kaldır"
|
||||
|
||||
@@ -151,6 +151,12 @@ UninstPage custom un.UnPageUserAppData un.UnPageUserAppDataLeave
|
||||
!include ${source_path}/admin/win/nsi/l10n/languages.nsh
|
||||
!include ${source_path}/admin/win/nsi/l10n/declarations.nsh
|
||||
|
||||
; Set version strings with english locale
|
||||
VIProductVersion "${VERSION}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "${APPLICATION_NAME}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "${APPLICATION_VENDOR}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION}"
|
||||
|
||||
!macro SETLANG un
|
||||
Function ${un}SetLang
|
||||
# load the selected language file
|
||||
@@ -407,7 +413,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${QT_DLL_PATH}\Qt5Xml.dll"
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng15-15.dll"
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata51.dll"
|
||||
File "${MING_BIN}\icui18n51.dll"
|
||||
File "${MING_BIN}\icuuc51.dll"
|
||||
@@ -415,7 +421,6 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
File "${MING_BIN}\libpcre16-0.dll"
|
||||
File "${MING_BIN}\libpng15-15.dll"
|
||||
File "${MING_BIN}\libproxy.dll"
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
@@ -442,6 +447,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
;MinGW stuff
|
||||
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwinpthread-1.dll"
|
||||
|
||||
; CSync configs
|
||||
File "${SOURCE_PATH}/sync-exclude.lst"
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#cmakedefine HAVE_UTIMES 1
|
||||
#cmakedefine HAVE_LSTAT 1
|
||||
#cmakedefine HAVE_FNMATCH 1
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ICONV 1
|
||||
#cmakedefine HAVE_ICONV_CONST 1
|
||||
|
||||
@@ -31,5 +30,6 @@
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ASPRINTF 1
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
|
||||
@@ -191,15 +191,12 @@ int csync_init(CSYNC *ctx) {
|
||||
ctx->local.type = LOCAL_REPLICA;
|
||||
|
||||
if ( !ctx->options.local_only_mode) {
|
||||
owncloud_init(csync_get_auth_callback(ctx), csync_get_userdata(ctx));
|
||||
owncloud_init(csync_get_userdata(ctx));
|
||||
ctx->remote.type = REMOTE_REPLICA;
|
||||
} else {
|
||||
ctx->remote.type = LOCAL_REPLICA;
|
||||
}
|
||||
|
||||
if (ctx->options.timeout)
|
||||
csync_vio_set_property(ctx, "timeout", &ctx->options.timeout);
|
||||
|
||||
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
rc = -1;
|
||||
@@ -280,11 +277,6 @@ int csync_update(CSYNC *ctx) {
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
if (rc < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* update detection for remote replica */
|
||||
if( ! ctx->options.local_only_mode ) {
|
||||
csync_gettime(&start);
|
||||
@@ -447,6 +439,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
trav.rename_path = cur->destpath;
|
||||
trav.etag = cur->etag;
|
||||
trav.file_id = cur->file_id;
|
||||
trav.inode = cur->inode;
|
||||
|
||||
trav.error_status = cur->error_status;
|
||||
trav.should_update_etag = cur->should_update_etag;
|
||||
|
||||
@@ -170,6 +170,7 @@ enum csync_notify_type_e {
|
||||
struct csync_tree_walk_file_s {
|
||||
const char *path;
|
||||
int64_t size;
|
||||
int64_t inode;
|
||||
time_t modtime;
|
||||
#ifdef _WIN32
|
||||
uint32_t uid;
|
||||
|
||||
@@ -229,6 +229,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
|
||||
type = CSYNC_FILE_EXCLUDE_LIST;
|
||||
if (strlen(pattern) < 1) {
|
||||
SAFE_FREE(pattern_stored);
|
||||
continue;
|
||||
}
|
||||
/* Ecludes starting with ']' means it can be cleanup */
|
||||
@@ -264,6 +265,9 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
|
||||
if (bname == NULL || dname == NULL) {
|
||||
match = CSYNC_NOT_EXCLUDED;
|
||||
SAFE_FREE(bname);
|
||||
SAFE_FREE(dname);
|
||||
SAFE_FREE(pattern_stored);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect
|
||||
int _connected = 0; /* flag to indicate if a connection exists, ie.
|
||||
the dav_session is valid */
|
||||
|
||||
csync_auth_callback _authcb;
|
||||
|
||||
void *_userdata;
|
||||
long long chunked_total_size = 0;
|
||||
long long chunked_done = 0;
|
||||
@@ -123,6 +123,7 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
char buf[MAX(NE_SSL_DIGESTLEN, NE_ABUFSIZ)];
|
||||
int ret = -1;
|
||||
const ne_ssl_certificate *cert = certificate;
|
||||
csync_auth_callback authcb = NULL;
|
||||
|
||||
(void) userdata;
|
||||
memset( problem, 0, LEN );
|
||||
@@ -160,11 +161,14 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
}
|
||||
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
|
||||
|
||||
if( _authcb ){
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
}
|
||||
if( authcb ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*_authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
if( buf[0] == 'y' || buf[0] == 'Y') {
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -184,6 +188,8 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
char *username, char *password)
|
||||
{
|
||||
char buf[NE_ABUFSIZ];
|
||||
csync_auth_callback authcb = NULL;
|
||||
int re = attempt;
|
||||
|
||||
(void) userdata;
|
||||
(void) realm;
|
||||
@@ -199,24 +205,29 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||
strcpy( password, dav_session.pwd );
|
||||
}
|
||||
} else if( _authcb != NULL ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*_authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
||||
strcpy( username, buf );
|
||||
}
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*_authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
|
||||
if( strlen(buf) < NE_ABUFSIZ) {
|
||||
strcpy( password, buf );
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBDAV("I can not authenticate!");
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
}
|
||||
if( authcb != NULL ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
||||
strcpy( username, buf );
|
||||
}
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
|
||||
if( strlen(buf) < NE_ABUFSIZ) {
|
||||
strcpy( password, buf );
|
||||
}
|
||||
} else {
|
||||
re = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return attempt;
|
||||
return re;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -508,10 +519,10 @@ static int dav_connect(const char *base_url) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dav_session.read_timeout == 0)
|
||||
dav_session.read_timeout = 300; // set 300 seconds as default.
|
||||
|
||||
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
|
||||
if (dav_session.read_timeout != 0) {
|
||||
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
|
||||
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
|
||||
}
|
||||
|
||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
||||
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||
@@ -685,7 +696,7 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
ret = NE_CONNECT;
|
||||
set_error_message(req_status->reason_phrase);
|
||||
}
|
||||
DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
|
||||
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
|
||||
} else {
|
||||
if( ret == NE_ERROR && req_status->code == 404) {
|
||||
errno = ENOENT;
|
||||
@@ -982,8 +993,10 @@ int owncloud_commit(void) {
|
||||
|
||||
clean_caches();
|
||||
|
||||
if( dav_session.ctx )
|
||||
ne_session_destroy( dav_session.ctx );
|
||||
if( dav_session.ctx ) {
|
||||
ne_forget_auth(dav_session.ctx);
|
||||
ne_session_destroy( dav_session.ctx );
|
||||
}
|
||||
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
|
||||
|
||||
dav_session.ctx = 0;
|
||||
@@ -1047,10 +1060,9 @@ int owncloud_set_property(const char *key, void *data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void owncloud_init(csync_auth_callback cb, void *userdata) {
|
||||
void owncloud_init(void *userdata) {
|
||||
|
||||
_userdata = userdata;
|
||||
_authcb = cb;
|
||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||
|
||||
memset(&dav_session, 0, sizeof(dav_session));
|
||||
|
||||
@@ -173,7 +173,7 @@ int owncloud_closedir(csync_vio_handle_t *dhandle);
|
||||
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf);
|
||||
int owncloud_commit(void);
|
||||
char *owncloud_error_string(void);
|
||||
void owncloud_init(csync_auth_callback cb, void *userdata);
|
||||
void owncloud_init(void *userdata);
|
||||
int owncloud_set_property(const char *key, void *data);
|
||||
|
||||
#endif /* CSYNC_OWNCLOUD_H */
|
||||
|
||||
@@ -236,13 +236,12 @@ static void propfind_results_recursive(void *userdata,
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
|
||||
} else {
|
||||
/* DEBUG_WEBDAV("results_recursive No parent %s found for child %s", parentPath, newres->uri); */
|
||||
resource_free(newres);
|
||||
newres = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resource_free(newres);
|
||||
newres = NULL;
|
||||
}
|
||||
|
||||
void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
|
||||
@@ -183,6 +183,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if( !c_streq(cur->file_id, "") ) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
@@ -191,7 +192,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if( !c_streq(cur->file_id, "") ) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
|
||||
other->inode = cur->inode;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
|
||||
@@ -237,8 +238,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
/* file on other replica is changed or new */
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
if (other->type == CSYNC_VIO_FILE_TYPE_DIRECTORY &&
|
||||
cur->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
||||
if (other->type == CSYNC_FTW_TYPE_DIR &&
|
||||
cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
is_equal_files = (other->modtime == cur->modtime);
|
||||
} else {
|
||||
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
|
||||
@@ -248,8 +249,12 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
|
||||
if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag);
|
||||
cur->should_update_etag = true; /* update DB */
|
||||
/* update DB with new etag from remote */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
other->should_update_etag = true;
|
||||
} else {
|
||||
cur->should_update_etag = true;
|
||||
}
|
||||
} else if(ctx->current == REMOTE_REPLICA) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
@@ -68,12 +69,11 @@ static void _csync_win32_hide_file( const char *file ) {
|
||||
fileName = c_utf8_to_locale( file );
|
||||
dwAttrs = GetFileAttributesW(fileName);
|
||||
|
||||
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
|
||||
|
||||
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
}
|
||||
|
||||
c_free_locale_string(fileName);
|
||||
#else
|
||||
(void) file;
|
||||
@@ -155,6 +155,8 @@ static int _csync_statedb_check(const char *statedb) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
/* if it comes here, the database is broken and should be recreated. */
|
||||
_tunlink(wstatedb);
|
||||
@@ -529,7 +531,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
if( rc != SQLITE_DONE ) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%ld entries read below path %s from db.", cnt, path);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
SAFE_FREE(likepath);
|
||||
|
||||
@@ -274,8 +274,13 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
} else {
|
||||
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
/* tmp might point to malloc mem, so free it here before reusing tmp */
|
||||
SAFE_FREE(tmp);
|
||||
|
||||
/* check if it's a file and has been renamed */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
||||
|
||||
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
|
||||
|
||||
/* translate the file type between the two stat types csync has. */
|
||||
@@ -476,7 +481,6 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
|
||||
/* File tree walker */
|
||||
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
unsigned int depth) {
|
||||
char errbuf[256] = {0};
|
||||
char *filename = NULL;
|
||||
char *d_name = NULL;
|
||||
csync_vio_handle_t *dh = NULL;
|
||||
@@ -520,10 +524,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
||||
}
|
||||
} else {
|
||||
C_STRERROR(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
|
||||
"opendir failed for %s - %s (errno %d)",
|
||||
uri, errbuf, errno);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
@@ -671,7 +672,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->current_fs && (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
|
||||
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
|
||||
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
|
||||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW ||
|
||||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
|
||||
ctx->current_fs->should_update_etag = true;
|
||||
|
||||
@@ -113,12 +113,12 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
|
||||
fileName = c_utf8_to_locale( file );
|
||||
dwAttrs = GetFileAttributesW(fileName);
|
||||
|
||||
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
|
||||
|
||||
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
}
|
||||
|
||||
c_free_locale_string(fileName);
|
||||
@@ -182,6 +182,7 @@ csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
|
||||
}
|
||||
|
||||
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
|
||||
csync_file_locked_or_open_ext = f;
|
||||
}
|
||||
|
||||
@@ -204,9 +204,9 @@ void hbf_free_transfer( hbf_transfer_t *transfer ) {
|
||||
|
||||
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
|
||||
hbf_block_t *block = transfer->block_arr[cnt];
|
||||
if( !block ) continue;
|
||||
if( block->http_error_msg ) free( block->http_error_msg );
|
||||
if( block->etag ) free( block->etag );
|
||||
if( block ) free(block);
|
||||
}
|
||||
free( transfer->block_arr );
|
||||
free( transfer->url );
|
||||
@@ -536,8 +536,8 @@ Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const cha
|
||||
} else {
|
||||
state = HBF_MEMORY_FAIL;
|
||||
}
|
||||
free( transfer_url );
|
||||
}
|
||||
free( transfer_url );
|
||||
}
|
||||
|
||||
/* do the source file validation finally (again). */
|
||||
|
||||
@@ -55,9 +55,6 @@
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
/** Macro to make strerror_r work with -Werror=unused-result */
|
||||
#define C_STRERROR(errno, buf, size) if(strerror_r(errno, buf, size)) {}
|
||||
|
||||
/**
|
||||
* This is a hack to fix warnings. The idea is to use this everywhere that we
|
||||
* get the "discarding const" warning by the compiler. That doesn't actually
|
||||
|
||||
@@ -135,7 +135,8 @@ int c_utimes(const char *uri, const struct timeval *times) {
|
||||
if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) {
|
||||
//can this happen?
|
||||
errno=ENOENT;
|
||||
CloseHandle(hFile);
|
||||
CloseHandle(hFile);
|
||||
c_free_locale_string(wuri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,11 +113,6 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||
if (rc < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d", errno);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Win32: STAT-inode for %s: %llu", uri, buf->inode );
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -240,6 +240,9 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
|
||||
buf->inode = FileIndex.QuadPart;
|
||||
|
||||
buf->size = (fileInfo.nFileSizeHigh * (int64_t)(MAXDWORD+1)) + fileInfo.nFileSizeLow;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
|
||||
/* Get the file time with a win32 call rather than through stat. See
|
||||
* http://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting
|
||||
* for deeper explanation.
|
||||
@@ -257,6 +260,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
|
||||
}
|
||||
|
||||
c_free_locale_string(wuri);
|
||||
CloseHandle(h);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -243,19 +243,6 @@ static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void check_csync_statedb_get_stat_by_inode(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_file_stat_t *tmp;
|
||||
|
||||
tmp = csync_statedb_get_stat_by_inode(csync, (ino_t) 23);
|
||||
assert_non_null(tmp);
|
||||
|
||||
assert_int_equal(tmp->phash, 42);
|
||||
assert_int_equal(tmp->inode, 23);
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
|
||||
{
|
||||
@@ -272,14 +259,10 @@ int torture_run_tests(void)
|
||||
unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_create_error, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_insert_statement, setup, teardown),
|
||||
/* unit_test_setup_teardown(check_csync_statedb_is_empty, setup, teardown), */
|
||||
/* unit_test_setup_teardown(check_csync_statedb_create_tables, setup, teardown), */
|
||||
unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
|
||||
/* unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash, setup_db, teardown), */
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
|
||||
/* unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode, setup_db, teardown), */
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
|
||||
};
|
||||
|
||||
|
||||
@@ -12,12 +12,15 @@ if(SPHINX_FOUND)
|
||||
# assets
|
||||
set(LATEX_LOGO "${CMAKE_CURRENT_SOURCE_DIR}/logo-blue.pdf")
|
||||
|
||||
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_MAN_DIR} DESTINATION ${CMAKE_INSTALL_MANDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" conf.py @ONLY)
|
||||
|
||||
if(WITH_DOC)
|
||||
add_custom_target(doc ALL DEPENDS doc-html doc-man COMMENT "Building documentation...")
|
||||
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
install(DIRECTORY ${SPHINX_MAN_DIR} DESTINATION ${CMAKE_INSTALL_MANDIR})
|
||||
else(WITH_DOC)
|
||||
add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...")
|
||||
endif(WITH_DOC)
|
||||
@@ -39,9 +42,6 @@ if(SPHINX_FOUND)
|
||||
add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf
|
||||
DEPENDS doc-latex )
|
||||
add_dependencies(doc doc-pdf)
|
||||
if (WITH_DOC)
|
||||
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
endif (WITH_DOC)
|
||||
endif(PDFLATEX_FOUND)
|
||||
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
|
||||
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
|
||||
@@ -53,9 +53,6 @@ if(SPHINX_FOUND)
|
||||
${SPHINX_QCH_DIR}/*.qhcp
|
||||
DEPENDS doc-qch-sphinx )
|
||||
add_dependencies(doc doc-qch)
|
||||
if (WITH_DOC)
|
||||
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
endif (WITH_DOC)
|
||||
endif()
|
||||
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
|
||||
-q -c . -b html
|
||||
|
||||
@@ -134,3 +134,25 @@ log line contains a lot of information of every request and it's result.
|
||||
More information about the apache logging can be found at
|
||||
``http://httpd.apache.org/docs/current/logs.html``.
|
||||
|
||||
Core Dumps
|
||||
----------
|
||||
|
||||
In case of crashes of the client software, having a core dump helps to
|
||||
debug the issue tremendously.
|
||||
|
||||
The client is able to write a core dump in case of crashing on Linux and
|
||||
MacOSX. To enable that, the environment variable ``OWNCLOUD_CORE_DUMP`` has
|
||||
to be defined.
|
||||
|
||||
For example
|
||||
|
||||
```
|
||||
OWNCLOUD_CORE_DUMP=1 owncloud
|
||||
```
|
||||
|
||||
starts the client with core dumping enabled. Core dumps appear in the
|
||||
current working directory, and since they can be fairly large, it is
|
||||
important to have plenty of disk space when running with dumps enabled.
|
||||
|
||||
If a core dump file should be transfered back to the developers it
|
||||
should be compressed properly before.
|
||||
|
||||
2
src/3rdparty/fancylineedit/fancylineedit.cpp
vendored
2
src/3rdparty/fancylineedit/fancylineedit.cpp
vendored
@@ -317,7 +317,7 @@ void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
|
||||
// IconButton - helper class to represent a clickable icon
|
||||
|
||||
IconButton::IconButton(QWidget *parent)
|
||||
: QAbstractButton(parent), m_autoHide(false)
|
||||
: QAbstractButton(parent), m_iconOpacity(0), m_autoHide(false)
|
||||
{
|
||||
setCursor(Qt::ArrowCursor);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
2
src/3rdparty/qtlockedfile/README.txt
vendored
2
src/3rdparty/qtlockedfile/README.txt
vendored
@@ -1,5 +1,5 @@
|
||||
This is the src directory of the QtLockedFile
|
||||
solution integrated over from Qt's Qt Creator.
|
||||
solution integrated over from Qt's Qt Creator.
|
||||
|
||||
It is required by the QtSingleApplication solution.
|
||||
|
||||
|
||||
41
src/3rdparty/qtlockedfile/qtlockedfile.cpp
vendored
41
src/3rdparty/qtlockedfile/qtlockedfile.cpp
vendored
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
|
||||
41
src/3rdparty/qtlockedfile/qtlockedfile.h
vendored
41
src/3rdparty/qtlockedfile/qtlockedfile.h
vendored
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLOCKEDFILE_H
|
||||
#define QTLOCKEDFILE_H
|
||||
|
||||
11
src/3rdparty/qtlockedfile/qtlockedfile.pri
vendored
Normal file
11
src/3rdparty/qtlockedfile/qtlockedfile.pri
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
HEADERS += $$PWD/qtlockedfile.h
|
||||
SOURCES += $$PWD/qtlockedfile.cpp
|
||||
|
||||
unix:SOURCES += $$PWD/qtlockedfile_unix.cpp
|
||||
win32:SOURCES += $$PWD/qtlockedfile_win.cpp
|
||||
|
||||
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
|
||||
DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport)
|
||||
}
|
||||
42
src/3rdparty/qtlockedfile/qtlockedfile_unix.cpp
vendored
42
src/3rdparty/qtlockedfile/qtlockedfile_unix.cpp
vendored
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
@@ -96,6 +95,7 @@ bool QtLockedFile::unlock()
|
||||
}
|
||||
|
||||
m_lock_mode = NoLock;
|
||||
remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
44
src/3rdparty/qtlockedfile/qtlockedfile_win.cpp
vendored
44
src/3rdparty/qtlockedfile/qtlockedfile_win.cpp
vendored
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
@@ -50,7 +49,7 @@ static QString errorCodeToString(DWORD errorCode)
|
||||
if (data != 0)
|
||||
LocalFree(data);
|
||||
|
||||
if (result.endsWith('\n'))
|
||||
if (result.endsWith(QLatin1Char('\n')))
|
||||
result.truncate(result.length() - 1);
|
||||
|
||||
return result;
|
||||
@@ -168,6 +167,7 @@ bool QtLockedFile::unlock()
|
||||
}
|
||||
|
||||
m_lock_mode = QtLockedFile::NoLock;
|
||||
remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
2
src/3rdparty/qtsingleapplication/README.txt
vendored
2
src/3rdparty/qtsingleapplication/README.txt
vendored
@@ -1,5 +1,5 @@
|
||||
This is the src directory of the QtSingleApplication solution
|
||||
integrated over from Qt's Qt Creator project.
|
||||
integrated over from Qt's Qt Creator project.
|
||||
|
||||
It additionally requires the QtLockedFile solution.
|
||||
|
||||
|
||||
102
src/3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
102
src/3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlocalpeer.h"
|
||||
|
||||
@@ -47,7 +46,31 @@ static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||
|
||||
namespace SharedTools {
|
||||
|
||||
const char *QtLocalPeer::ack = "ack";
|
||||
static const char ack[] = "ack";
|
||||
|
||||
QString QtLocalPeer::appSessionId(const QString &appId)
|
||||
{
|
||||
QByteArray idc = appId.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
//### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
|
||||
|
||||
QString res = QLatin1String("qtsingleapplication-")
|
||||
+ QString::number(idNum, 16);
|
||||
#if defined(Q_OS_WIN)
|
||||
if (!pProcessIdToSessionId) {
|
||||
QLibrary lib(QLatin1String("kernel32"));
|
||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||
}
|
||||
if (pProcessIdToSessionId) {
|
||||
DWORD sessionId = 0;
|
||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
res += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||
}
|
||||
#else
|
||||
res += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
|
||||
: QObject(parent), id(appId)
|
||||
@@ -55,26 +78,7 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
|
||||
if (id.isEmpty())
|
||||
id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
|
||||
|
||||
QByteArray idc = id.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
//### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
|
||||
|
||||
socketName = QLatin1String("qtsingleapplication-")
|
||||
+ QString::number(idNum, 16);
|
||||
#if defined(Q_OS_WIN)
|
||||
if (!pProcessIdToSessionId) {
|
||||
QLibrary lib("kernel32");
|
||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||
}
|
||||
if (pProcessIdToSessionId) {
|
||||
DWORD sessionId = 0;
|
||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||
}
|
||||
#else
|
||||
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||
#endif
|
||||
|
||||
socketName = appSessionId(id);
|
||||
server = new QLocalServer(this);
|
||||
QString lockName = QDir(QDir::tempPath()).absolutePath()
|
||||
+ QLatin1Char('/') + socketName
|
||||
@@ -100,7 +104,7 @@ bool QtLocalPeer::isClient()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||
bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block)
|
||||
{
|
||||
if (!isClient())
|
||||
return false;
|
||||
@@ -130,6 +134,8 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||
bool res = socket.waitForBytesWritten(timeout);
|
||||
res &= socket.waitForReadyRead(timeout); // wait for ack
|
||||
res &= (socket.read(qstrlen(ack)) == ack);
|
||||
if (block) // block until peer disconnects
|
||||
socket.waitForDisconnected(-1);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -140,8 +146,11 @@ void QtLocalPeer::receiveConnection()
|
||||
return;
|
||||
|
||||
// Why doesn't Qt have a blocking stream that takes care of this shait???
|
||||
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32)))
|
||||
socket->waitForReadyRead();
|
||||
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32))) {
|
||||
if (!socket->isValid()) // stale request
|
||||
return;
|
||||
socket->waitForReadyRead(1000);
|
||||
}
|
||||
QDataStream ds(socket);
|
||||
QByteArray uMsg;
|
||||
quint32 remaining;
|
||||
@@ -166,8 +175,7 @@ void QtLocalPeer::receiveConnection()
|
||||
QString message = QString::fromUtf8(uMsg.constData(), uMsg.size());
|
||||
socket->write(ack, qstrlen(ack));
|
||||
socket->waitForBytesWritten(1000);
|
||||
delete socket;
|
||||
emit messageReceived(message); // ##(might take a long time to return)
|
||||
emit messageReceived(message, socket); // ##(might take a long time to return)
|
||||
}
|
||||
|
||||
} // namespace SharedTools
|
||||
|
||||
51
src/3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
51
src/3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
@@ -1,34 +1,33 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
#include <qtlockedfile.h>
|
||||
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
@@ -43,12 +42,13 @@ class QtLocalPeer : public QObject
|
||||
public:
|
||||
explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout);
|
||||
bool sendMessage(const QString &message, int timeout, bool block);
|
||||
QString applicationId() const
|
||||
{ return id; }
|
||||
static QString appSessionId(const QString &appId);
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
void messageReceived(const QString &message, QObject *socket);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void receiveConnection();
|
||||
@@ -58,9 +58,6 @@ protected:
|
||||
QString socketName;
|
||||
QLocalServer* server;
|
||||
QtLockedFile lockFile;
|
||||
|
||||
private:
|
||||
static const char* ack;
|
||||
};
|
||||
|
||||
} // namespace SharedTools
|
||||
|
||||
@@ -1,96 +1,123 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtsingleapplication.h"
|
||||
#include "qtlocalpeer.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <qtlockedfile.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileOpenEvent>
|
||||
#include <QSharedMemory>
|
||||
#include <QWidget>
|
||||
|
||||
namespace SharedTools {
|
||||
|
||||
void QtSingleApplication::sysInit(const QString &appId)
|
||||
static const int instancesSize = 1024;
|
||||
|
||||
static QString instancesLockFilename(const QString &appSessionId)
|
||||
{
|
||||
actWin = 0;
|
||||
firstPeer = new QtLocalPeer(this, appId);
|
||||
connect(firstPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
|
||||
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid(), 10));
|
||||
connect(pidPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
|
||||
const QChar slash(QLatin1Char('/'));
|
||||
QString res = QDir::tempPath();
|
||||
if (!res.endsWith(slash))
|
||||
res += slash;
|
||||
return res + appSessionId + QLatin1String("-instances");
|
||||
}
|
||||
|
||||
|
||||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
||||
: QApplication(argc, argv, GUIenabled)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
|
||||
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
: QApplication(argc, argv),
|
||||
firstPeer(-1),
|
||||
pidPeer(0)
|
||||
{
|
||||
this->appId = appId;
|
||||
sysInit(appId);
|
||||
|
||||
const QString appSessionId = QtLocalPeer::appSessionId(appId);
|
||||
|
||||
// This shared memory holds a zero-terminated array of active (or crashed) instances
|
||||
instances = new QSharedMemory(appSessionId, this);
|
||||
actWin = 0;
|
||||
block = false;
|
||||
|
||||
// First instance creates the shared memory, later instances attach to it
|
||||
const bool created = instances->create(instancesSize);
|
||||
if (!created) {
|
||||
if (!instances->attach()) {
|
||||
qWarning() << "Failed to initialize instances shared memory: "
|
||||
<< instances->errorString();
|
||||
delete instances;
|
||||
instances = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// QtLockedFile is used to workaround QTBUG-10364
|
||||
QtLockedFile lockfile(instancesLockFilename(appSessionId));
|
||||
|
||||
lockfile.open(QtLockedFile::ReadWrite);
|
||||
lockfile.lock(QtLockedFile::WriteLock);
|
||||
qint64 *pids = static_cast<qint64 *>(instances->data());
|
||||
if (!created) {
|
||||
// Find the first instance that it still running
|
||||
// The whole list needs to be iterated in order to append to it
|
||||
for (; *pids; ++pids) {
|
||||
if (firstPeer == -1 && isRunning(*pids))
|
||||
firstPeer = *pids;
|
||||
}
|
||||
}
|
||||
// Add current pid to list and terminate it
|
||||
*pids++ = QCoreApplication::applicationPid();
|
||||
*pids = 0;
|
||||
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') +
|
||||
QString::number(QCoreApplication::applicationPid()));
|
||||
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*)));
|
||||
pidPeer->isClient();
|
||||
lockfile.unlock();
|
||||
}
|
||||
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
|
||||
: QApplication(argc, argv, type)
|
||||
QtSingleApplication::~QtSingleApplication()
|
||||
{
|
||||
sysInit();
|
||||
if (!instances)
|
||||
return;
|
||||
const qint64 appPid = QCoreApplication::applicationPid();
|
||||
QtLockedFile lockfile(instancesLockFilename(QtLocalPeer::appSessionId(appId)));
|
||||
lockfile.open(QtLockedFile::ReadWrite);
|
||||
lockfile.lock(QtLockedFile::WriteLock);
|
||||
// Rewrite array, removing current pid and previously crashed ones
|
||||
qint64 *pids = static_cast<qint64 *>(instances->data());
|
||||
qint64 *newpids = pids;
|
||||
for (; *pids; ++pids) {
|
||||
if (*pids != appPid && isRunning(*pids))
|
||||
*newpids++ = *pids;
|
||||
}
|
||||
*newpids = 0;
|
||||
lockfile.unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(Q_WS_X11)
|
||||
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
|
||||
: QApplication(dpy, visual, colormap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, argc, argv, visual, cmap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId,
|
||||
int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE colormap)
|
||||
: QApplication(dpy, argc, argv, visual, colormap)
|
||||
{
|
||||
this->appId = appId;
|
||||
sysInit(appId);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool QtSingleApplication::event(QEvent *event)
|
||||
{
|
||||
@@ -104,31 +131,26 @@ bool QtSingleApplication::event(QEvent *event)
|
||||
|
||||
bool QtSingleApplication::isRunning(qint64 pid)
|
||||
{
|
||||
if (pid == -1)
|
||||
return firstPeer->isClient();
|
||||
if (pid == -1) {
|
||||
pid = firstPeer;
|
||||
if (pid == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
|
||||
return peer.isClient();
|
||||
}
|
||||
|
||||
void QtSingleApplication::initialize(bool)
|
||||
{
|
||||
firstPeer->isClient();
|
||||
pidPeer->isClient();
|
||||
}
|
||||
|
||||
bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid)
|
||||
{
|
||||
if (pid == -1)
|
||||
return firstPeer->sendMessage(message, timeout);
|
||||
if (pid == -1) {
|
||||
pid = firstPeer;
|
||||
if (pid == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
|
||||
return peer.sendMessage(message, timeout);
|
||||
}
|
||||
|
||||
QString QtSingleApplication::id() const
|
||||
{
|
||||
return firstPeer->applicationId();
|
||||
return peer.sendMessage(message, timeout, block);
|
||||
}
|
||||
|
||||
QString QtSingleApplication::applicationId() const
|
||||
@@ -136,16 +158,20 @@ QString QtSingleApplication::applicationId() const
|
||||
return appId;
|
||||
}
|
||||
|
||||
void QtSingleApplication::setBlock(bool value)
|
||||
{
|
||||
block = value;
|
||||
}
|
||||
|
||||
void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage)
|
||||
{
|
||||
actWin = aw;
|
||||
if (activateOnMessage) {
|
||||
connect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
|
||||
connect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
|
||||
} else {
|
||||
disconnect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
|
||||
disconnect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
|
||||
}
|
||||
if (!pidPeer)
|
||||
return;
|
||||
if (activateOnMessage)
|
||||
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
|
||||
else
|
||||
disconnect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _SHAREDTOOLS_SINGLEAPPLICATION
|
||||
#define _SHAREDTOOLS_SINGLEAPPLICATION
|
||||
#ifndef QTSINGLEAPPLICATION_H
|
||||
#define QTSINGLEAPPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QSharedMemory)
|
||||
|
||||
namespace SharedTools {
|
||||
|
||||
class QtLocalPeer;
|
||||
@@ -42,50 +43,37 @@ class QtSingleApplication : public QApplication
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
||||
QtSingleApplication(const QString &id, int &argc, char **argv);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QtSingleApplication(int &argc, char **argv, Type type);
|
||||
#endif
|
||||
#if defined(Q_WS_X11)
|
||||
explicit QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
|
||||
#endif
|
||||
~QtSingleApplication();
|
||||
|
||||
bool isRunning(qint64 pid = -1);
|
||||
|
||||
QString id() const;
|
||||
|
||||
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
|
||||
QWidget* activationWindow() const;
|
||||
bool event(QEvent *event);
|
||||
|
||||
QString applicationId() const;
|
||||
void setBlock(bool value);
|
||||
|
||||
public Q_SLOTS:
|
||||
bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1);
|
||||
void activateWindow();
|
||||
|
||||
//Obsolete methods:
|
||||
public:
|
||||
void initialize(bool = true);
|
||||
|
||||
#if defined(Q_WS_X11)
|
||||
QtSingleApplication(Display* dpy, const QString &id, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
#endif
|
||||
// end obsolete methods
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
void messageReceived(const QString &message, QObject *socket);
|
||||
void fileOpenRequest(const QString &file);
|
||||
|
||||
private:
|
||||
void sysInit(const QString &appId = QString());
|
||||
QtLocalPeer *firstPeer;
|
||||
QString instancesFileName(const QString &appId);
|
||||
|
||||
qint64 firstPeer;
|
||||
QSharedMemory *instances;
|
||||
QtLocalPeer *pidPeer;
|
||||
QWidget *actWin;
|
||||
QString appId;
|
||||
bool block;
|
||||
};
|
||||
|
||||
} // namespace SharedTools
|
||||
#endif // _SHAREDTOOLS_SINGLEAPPLICATION
|
||||
|
||||
#endif // QTSINGLEAPPLICATION_H
|
||||
|
||||
15
src/3rdparty/qtsingleapplication/qtsingleapplication.pri
vendored
Normal file
15
src/3rdparty/qtsingleapplication/qtsingleapplication.pri
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
|
||||
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
|
||||
|
||||
QT *= network
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
|
||||
isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
|
||||
|
||||
|
||||
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
|
||||
DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport)
|
||||
}
|
||||
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtsinglecoreapplication.h"
|
||||
#include "qtlocalpeer.h"
|
||||
@@ -37,6 +36,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
||||
: QCoreApplication(argc, argv)
|
||||
{
|
||||
peer = new QtLocalPeer(this);
|
||||
block = false;
|
||||
connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ bool QtSingleCoreApplication::isRunning()
|
||||
|
||||
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
||||
{
|
||||
return peer->sendMessage(message, timeout);
|
||||
return peer->sendMessage(message, timeout, block);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,4 +66,9 @@ QString QtSingleCoreApplication::id() const
|
||||
return peer->applicationId();
|
||||
}
|
||||
|
||||
void QtSingleCoreApplication::setBlock(bool value)
|
||||
{
|
||||
block = value;
|
||||
}
|
||||
|
||||
} // namespace SharedTools
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
/**************************************************************************
|
||||
/****************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: http://www.qt-project.org/
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
@@ -44,6 +43,7 @@ public:
|
||||
|
||||
bool isRunning();
|
||||
QString id() const;
|
||||
void setBlock(bool value);
|
||||
|
||||
public Q_SLOTS:
|
||||
bool sendMessage(const QString &message, int timeout = 5000);
|
||||
@@ -55,6 +55,7 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
QtLocalPeer* peer;
|
||||
bool block;
|
||||
};
|
||||
|
||||
} // namespace SharedTools
|
||||
|
||||
14
src/3rdparty/qtsingleapplication/qtsinglecoreapplication.pri
vendored
Normal file
14
src/3rdparty/qtsingleapplication/qtsinglecoreapplication.pri
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
|
||||
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
|
||||
|
||||
QT *= network
|
||||
|
||||
gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
|
||||
isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
|
||||
|
||||
|
||||
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
|
||||
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@@ -103,6 +104,7 @@ set(libsync_SRCS
|
||||
mirall/quotainfo.cpp
|
||||
mirall/clientproxy.cpp
|
||||
mirall/syncrunfilelog.cpp
|
||||
mirall/cookiejar.cpp
|
||||
creds/dummycredentials.cpp
|
||||
creds/abstractcredentials.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
@@ -120,11 +122,8 @@ else()
|
||||
${libsync_SRCS}
|
||||
creds/httpcredentials.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/shibboleth/authenticationdialog.cpp
|
||||
creds/shibboleth/shibbolethuserjob.cpp
|
||||
)
|
||||
@@ -195,6 +194,14 @@ if(NEON_FOUND)
|
||||
endif()
|
||||
|
||||
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
|
||||
GENERATE_EXPORT_HEADER( ${synclib_NAME}
|
||||
BASE_NAME ${synclib_NAME}
|
||||
EXPORT_MACRO_NAME OWNCLOUDSYNC_EXPORT
|
||||
EXPORT_FILE_NAME owncloudlib.h
|
||||
STATIC_DEFINE OWNCLOUD_BUILT_AS_STATIC
|
||||
)
|
||||
|
||||
|
||||
if(TOKEN_AUTH_ONLY)
|
||||
qt5_use_modules(${synclib_NAME} Network Xml Sql)
|
||||
else()
|
||||
|
||||
@@ -141,7 +141,11 @@ void HttpCredentials::syncContextPreStart (CSYNC* ctx)
|
||||
|
||||
bool HttpCredentials::changed(AbstractCredentials* credentials) const
|
||||
{
|
||||
HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials));
|
||||
HttpCredentials* other(qobject_cast< HttpCredentials* >(credentials));
|
||||
|
||||
if (!other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!other || (other->user() != this->user())) {
|
||||
return true;
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkCookieJar>
|
||||
|
||||
#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; // this line and the line above replace all cookies with self and then add the shibboleth cookie (filtering the current shib 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
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_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
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <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
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_CREDS_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
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "creds/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
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_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
|
||||
@@ -47,7 +47,7 @@ bool ShibbolethUserJob::finished()
|
||||
}
|
||||
|
||||
QString user = json.value("ocs").toMap().value("data").toMap().value("id").toString();
|
||||
qDebug() << "cloud/user: " << json << "->" << user;
|
||||
//qDebug() << "cloud/user: " << json << "->" << user;
|
||||
emit userFetched(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,96 +14,75 @@
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QWebFrame>
|
||||
#include <QWebPage>
|
||||
#include <QMessageBox>
|
||||
#include <QAuthenticator>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "creds/shibboleth/shibbolethcookiejar.h"
|
||||
#include "creds/shibboleth/shibbolethwebview.h"
|
||||
#include "creds/shibboleth/authenticationdialog.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "mirall/account.h"
|
||||
#include "mirall/logger.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/theme.h"
|
||||
|
||||
namespace Mirall
|
||||
{
|
||||
|
||||
void ShibbolethWebView::setup(Account *account, ShibbolethCookieJar* jar)
|
||||
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
|
||||
: QWebView(parent)
|
||||
, _account(account)
|
||||
, _accepted(false)
|
||||
{
|
||||
_account = account;
|
||||
MirallAccessManager* nm = new MirallAccessManager(this);
|
||||
// we need our own QNAM, but the we offload the SSL error handling to
|
||||
// the account object, which already can do this
|
||||
connect(nm, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
|
||||
account, SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
|
||||
connect(nm, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
|
||||
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
|
||||
|
||||
// no minimize
|
||||
setWindowFlags(Qt::Dialog);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
QWebPage* page = new QWebPage(this);
|
||||
|
||||
jar->setParent(this);
|
||||
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
|
||||
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
|
||||
page->setNetworkAccessManager(account->networkAccessManager());
|
||||
connect(page, SIGNAL(loadStarted()),
|
||||
this, SLOT(slotLoadStarted()));
|
||||
connect(page, SIGNAL(loadFinished(bool)),
|
||||
this, SLOT(slotLoadFinished(bool)));
|
||||
|
||||
nm->setCookieJar(jar);
|
||||
page->setNetworkAccessManager(nm);
|
||||
|
||||
connect(page->networkAccessManager()->cookieJar(),
|
||||
SIGNAL(newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
|
||||
this, SLOT(onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
|
||||
page->mainFrame()->load(account->url());
|
||||
this->setPage(page);
|
||||
setWindowTitle(tr("%1 - Authenticate").arg(Theme::instance()->appNameGUI()));
|
||||
}
|
||||
|
||||
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
|
||||
: QWebView(parent)
|
||||
{
|
||||
setup(account, new ShibbolethCookieJar(this));
|
||||
// If we have a valid cookie, it's most likely expired. We can use this as
|
||||
// as a criteria to tell the user why the browser window pops up
|
||||
QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, ShibbolethCredentials::accountCookies(_account));
|
||||
if (shibCookie != QNetworkCookie()) {
|
||||
Logger::instance()->postOptionalGuiLog(tr("Reauthentication required"), tr("Your session has expired. You need to re-login to continue to use the client."));
|
||||
}
|
||||
}
|
||||
|
||||
ShibbolethWebView::~ShibbolethWebView()
|
||||
{
|
||||
slotLoadFinished();
|
||||
}
|
||||
|
||||
ShibbolethWebView::ShibbolethWebView(Account* account, ShibbolethCookieJar* jar, QWidget* parent)
|
||||
: QWebView(parent)
|
||||
{
|
||||
setup(account, 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 (url.host() == _account->url().host()) {
|
||||
QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, cookieList);
|
||||
if (shibCookie != QNetworkCookie()) {
|
||||
Q_EMIT shibbolethCookieReceived(shibCookie, _account);
|
||||
accept();
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!otherCookies.isEmpty()) {
|
||||
Q_EMIT otherCookiesReceived(otherCookies, url);
|
||||
}
|
||||
if (!shibCookie.name().isEmpty()) {
|
||||
Q_EMIT shibbolethCookieReceived(shibCookie, _account);
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethWebView::hideEvent(QHideEvent* event)
|
||||
void ShibbolethWebView::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_EMIT viewHidden();
|
||||
QWebView::hideEvent(event);
|
||||
if (!_accepted) {
|
||||
Q_EMIT rejected();
|
||||
}
|
||||
QWebView::closeEvent(event);
|
||||
}
|
||||
|
||||
void ShibbolethWebView::slotLoadStarted()
|
||||
@@ -125,21 +104,9 @@ void ShibbolethWebView::slotLoadFinished(bool success)
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethWebView::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
|
||||
void ShibbolethWebView::accept()
|
||||
{
|
||||
Q_UNUSED(reply)
|
||||
QUrl url = reply->url();
|
||||
// show only scheme, host and port
|
||||
QUrl reducedUrl;
|
||||
reducedUrl.setScheme(url.scheme());
|
||||
reducedUrl.setHost(url.host());
|
||||
reducedUrl.setPort(url.port());
|
||||
|
||||
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString(), this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
authenticator->setUser(dialog.user());
|
||||
authenticator->setPassword(dialog.password());
|
||||
}
|
||||
_accepted = true;
|
||||
}
|
||||
|
||||
} // ns Mirall
|
||||
|
||||
@@ -37,23 +37,24 @@ public:
|
||||
ShibbolethWebView(Account *account, ShibbolethCookieJar* jar, QWidget* parent = 0);
|
||||
~ShibbolethWebView();
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent* event);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
Q_SIGNALS:
|
||||
void shibbolethCookieReceived(const QNetworkCookie& cookie, Account* account);
|
||||
void viewHidden();
|
||||
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
void shibbolethCookieReceived(const QNetworkCookie &cookie, Account *account);
|
||||
void rejected();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
void slotLoadStarted();
|
||||
void slotLoadFinished(bool success = true);
|
||||
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
|
||||
void slotLoadFinished(bool success);
|
||||
|
||||
protected:
|
||||
void accept();
|
||||
|
||||
private:
|
||||
void setup(Account *account, ShibbolethCookieJar* jar);
|
||||
QPointer<Account> _account;
|
||||
bool _accepted;
|
||||
};
|
||||
|
||||
} // ns Mirall
|
||||
|
||||
@@ -16,18 +16,21 @@
|
||||
#include <QSettings>
|
||||
#include <QNetworkReply>
|
||||
#include <QMessageBox>
|
||||
#include <qdebug.h>
|
||||
#include <QAuthenticator>
|
||||
#include <QDebug>
|
||||
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "creds/shibboleth/shibbolethaccessmanager.h"
|
||||
#include "creds/shibboleth/authenticationdialog.h"
|
||||
#include "creds/shibboleth/shibbolethwebview.h"
|
||||
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||
#include "creds/shibboleth/shibbolethconfigfile.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "shibboleth/shibbolethuserjob.h"
|
||||
#include "creds/credentialscommon.h"
|
||||
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/account.h"
|
||||
#include "mirall/theme.h"
|
||||
#include "mirall/cookiejar.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <qt5keychain/keychain.h>
|
||||
@@ -43,7 +46,9 @@ namespace Mirall
|
||||
namespace
|
||||
{
|
||||
|
||||
const char userC[] = "user";
|
||||
// Not "user" because it has a special meaning for http
|
||||
const char userC[] = "shib_user";
|
||||
const char shibCookieNameC[] = "_shibsession_";
|
||||
|
||||
int shibboleth_redirect_callback(CSYNC* csync_ctx,
|
||||
const char* uri)
|
||||
@@ -65,7 +70,6 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
|
||||
Account *account = AccountManager::instance()->account();
|
||||
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
|
||||
|
||||
|
||||
if (!creds) {
|
||||
qDebug() << "Not a Shibboleth creds instance!";
|
||||
return 1;
|
||||
@@ -84,18 +88,10 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
|
||||
ShibbolethCredentials::ShibbolethCredentials()
|
||||
: AbstractCredentials(),
|
||||
_url(),
|
||||
_shibCookie(),
|
||||
_ready(false),
|
||||
_stillValid(false),
|
||||
_browser(0),
|
||||
_otherCookies()
|
||||
{}
|
||||
|
||||
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
|
||||
: _shibCookie(cookie),
|
||||
_ready(true),
|
||||
_browser(0),
|
||||
_otherCookies(otherCookies)
|
||||
_fetchJobInProgress(false),
|
||||
_browser(0)
|
||||
{}
|
||||
|
||||
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
|
||||
@@ -110,29 +106,11 @@ QByteArray ShibbolethCredentials::prepareCookieData() const
|
||||
// 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(AccountManager::instance()->account()->lastAuthCookies());
|
||||
QMap<QString, QString> uniqueCookies;
|
||||
Account *account = AccountManager::instance()->account();
|
||||
QList<QNetworkCookie> cookies = accountCookies(account);
|
||||
|
||||
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 += "; ";
|
||||
foreach(const QNetworkCookie &cookie, cookies) {
|
||||
cookiesAsString += cookie.toRawForm(QNetworkCookie::NameAndValueOnly) + QLatin1String("; ");
|
||||
}
|
||||
|
||||
return cookiesAsString.toLatin1();
|
||||
@@ -150,9 +128,13 @@ void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
|
||||
|
||||
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
|
||||
{
|
||||
ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials));
|
||||
ShibbolethCredentials* other(qobject_cast< ShibbolethCredentials* >(credentials));
|
||||
|
||||
if (!other || other->cookie() != this->cookie()) {
|
||||
if (!other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_shibCookie != other->_shibCookie || _user != other->_user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -169,24 +151,22 @@ QString ShibbolethCredentials::user() const
|
||||
return _user;
|
||||
}
|
||||
|
||||
QNetworkCookie ShibbolethCredentials::cookie() const
|
||||
{
|
||||
return _shibCookie;
|
||||
}
|
||||
|
||||
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
|
||||
{
|
||||
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie));
|
||||
|
||||
connect(this, SIGNAL(newCookie(QNetworkCookie)),
|
||||
qnam, SLOT(setCookie(QNetworkCookie)));
|
||||
QNetworkAccessManager* qnam(new MirallAccessManager);
|
||||
connect(qnam, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(slotReplyFinished(QNetworkReply*)));
|
||||
connect(qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
|
||||
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
|
||||
return qnam;
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotReplyFinished(QNetworkReply* r)
|
||||
{
|
||||
if (!_browser.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant target = r->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (target.isValid()) {
|
||||
_stillValid = false;
|
||||
@@ -203,10 +183,16 @@ bool ShibbolethCredentials::ready() const
|
||||
|
||||
void ShibbolethCredentials::fetch(Account *account)
|
||||
{
|
||||
|
||||
if(_fetchJobInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_user.isEmpty()) {
|
||||
_user = account->credentialSetting(QLatin1String(userC)).toString();
|
||||
}
|
||||
if (_ready) {
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
if (account) {
|
||||
@@ -219,6 +205,7 @@ void ShibbolethCredentials::fetch(Account *account)
|
||||
job->setProperty("account", QVariant::fromValue(account));
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
_fetchJobInProgress = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,44 +217,29 @@ bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
|
||||
|
||||
void ShibbolethCredentials::persist(Account* account)
|
||||
{
|
||||
ShibbolethConfigFile cfg;
|
||||
|
||||
cfg.storeCookies(_otherCookies);
|
||||
|
||||
storeShibCookie(_shibCookie, account);
|
||||
if (!_user.isEmpty())
|
||||
if (!_user.isEmpty()) {
|
||||
account->setCredentialSetting(QLatin1String(userC), _user);
|
||||
}
|
||||
}
|
||||
|
||||
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
|
||||
void ShibbolethCredentials::invalidateToken(Account *account)
|
||||
{
|
||||
Q_UNUSED(account)
|
||||
CookieJar *jar = static_cast<CookieJar*>(account->networkAccessManager()->cookieJar());
|
||||
jar->deleteCookie(_shibCookie);
|
||||
jar->clearSessionCookies();
|
||||
removeShibCookie(account);
|
||||
_shibCookie = QNetworkCookie();
|
||||
storeShibCookie(_shibCookie, account); // store/erase cookie
|
||||
|
||||
// ### access to ctx missing, but might not be required at all
|
||||
//csync_set_module_property(ctx, "session_key", "");
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::disposeBrowser()
|
||||
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shibCookie, Account *account)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
disconnect(_browser, SIGNAL(viewHidden()),
|
||||
this, SLOT(slotBrowserHidden()));
|
||||
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
|
||||
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
|
||||
_browser->hide();
|
||||
_browser->deleteLater();
|
||||
_browser = 0;
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie, Account* account)
|
||||
{
|
||||
disposeBrowser();
|
||||
_shibCookie = cookie;
|
||||
storeShibCookie(_shibCookie, account);
|
||||
Q_EMIT newCookie(_shibCookie);
|
||||
storeShibCookie(shibCookie, account);
|
||||
_shibCookie = shibCookie;
|
||||
addToCookieJar(shibCookie);
|
||||
|
||||
// Now fetch the user...
|
||||
// But we must first do a request to webdav so the session is enabled.
|
||||
@@ -304,21 +276,22 @@ void ShibbolethCredentials::slotUserFetched(const QString &user)
|
||||
|
||||
_stillValid = true;
|
||||
_ready = true;
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
}
|
||||
|
||||
|
||||
void ShibbolethCredentials::slotBrowserHidden()
|
||||
void ShibbolethCredentials::slotBrowserRejected()
|
||||
{
|
||||
disposeBrowser();
|
||||
_ready = false;
|
||||
_shibCookie = QNetworkCookie();
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::invalidateAndFetch(Account* account)
|
||||
{
|
||||
_ready = false;
|
||||
_fetchJobInProgress = true;
|
||||
|
||||
// delete the credentials, then in the slot fetch them again (which will trigger browser)
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
@@ -329,12 +302,30 @@ void ShibbolethCredentials::invalidateAndFetch(Account* account)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
|
||||
{
|
||||
Q_UNUSED(reply)
|
||||
QUrl url = reply->url();
|
||||
// show only scheme, host and port
|
||||
QUrl reducedUrl;
|
||||
reducedUrl.setScheme(url.scheme());
|
||||
reducedUrl.setHost(url.host());
|
||||
reducedUrl.setPort(url.port());
|
||||
|
||||
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
authenticator->setUser(dialog.user());
|
||||
authenticator->setPassword(dialog.password());
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job* job)
|
||||
{
|
||||
Account *account = qvariant_cast<Account*>(job->property("account"));
|
||||
|
||||
connect (this, SIGNAL(fetched()),
|
||||
this, SLOT(onFetched()));
|
||||
_fetchJobInProgress = false;
|
||||
// small hack to support the ShibbolethRefresher hack
|
||||
// we already rand fetch() with a valid account object,
|
||||
// and hence know the url on refresh
|
||||
@@ -355,16 +346,17 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
if (job->error() == QKeychain::NoError) {
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
|
||||
delete readJob->settings();
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(readJob->textData().toUtf8());
|
||||
if (cookies.count() > 0) {
|
||||
_shibCookie = cookies.first();
|
||||
addToCookieJar(_shibCookie);
|
||||
}
|
||||
// access
|
||||
job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job));
|
||||
|
||||
_ready = true;
|
||||
_stillValid = true;
|
||||
Q_EMIT newCookie(_shibCookie);
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
showLoginWindow(account);
|
||||
@@ -373,24 +365,51 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
|
||||
void ShibbolethCredentials::showLoginWindow(Account* account)
|
||||
{
|
||||
if (_browser) {
|
||||
if (!_browser.isNull()) {
|
||||
_browser->activateWindow();
|
||||
_browser->raise();
|
||||
// FIXME On OS X this does not raise properly
|
||||
return;
|
||||
}
|
||||
ShibbolethConfigFile cfg;
|
||||
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
|
||||
|
||||
CookieJar *jar = static_cast<CookieJar*>(account->networkAccessManager()->cookieJar());
|
||||
// When opening a new window clear all the session cookie that might keep the user from logging in
|
||||
// (or the session may already be open in the server, and there will not be redirect asking for the
|
||||
// real long term cookie we want to store)
|
||||
jar->clearSessionCookies();
|
||||
|
||||
_browser = new ShibbolethWebView(account);
|
||||
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
|
||||
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
|
||||
connect(_browser, SIGNAL(viewHidden()),
|
||||
this, SLOT(slotBrowserHidden()));
|
||||
// FIXME If the browser was hidden (e.g. user closed it) without us logging in, the logic gets stuck
|
||||
// and can only be unstuck by restarting the app or pressing "Sign in" (we should switch to offline but we don't)
|
||||
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)), Qt::QueuedConnection);
|
||||
connect(_browser, SIGNAL(rejected()), this, SLOT(slotBrowserRejected()));
|
||||
|
||||
_browser->show();
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> ShibbolethCredentials::accountCookies(Account *account)
|
||||
{
|
||||
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->url());
|
||||
}
|
||||
|
||||
QNetworkCookie ShibbolethCredentials::findShibCookie(Account *account, QList<QNetworkCookie> cookies)
|
||||
{
|
||||
if(cookies.isEmpty()) {
|
||||
cookies = accountCookies(account);
|
||||
}
|
||||
|
||||
Q_FOREACH(QNetworkCookie cookie, cookies) {
|
||||
if (cookie.name().startsWith(shibCookieNameC)) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
return QNetworkCookie();
|
||||
}
|
||||
|
||||
QByteArray ShibbolethCredentials::shibCookieName()
|
||||
{
|
||||
return QByteArray(shibCookieNameC);
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Account *account)
|
||||
{
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
@@ -402,5 +421,24 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Accoun
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::removeShibCookie(Account *account)
|
||||
{
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job));
|
||||
job->setKey(keychainKey(account->url().toString(), "shibAssertion"));
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::addToCookieJar(const QNetworkCookie &cookie)
|
||||
{
|
||||
QList<QNetworkCookie> cookies;
|
||||
cookies << cookie;
|
||||
Account *account = AccountManager::instance()->account();
|
||||
QNetworkCookieJar *jar = account->networkAccessManager()->cookieJar();
|
||||
jar->blockSignals(true); // otherwise we'd call ourselves
|
||||
jar->setCookiesFromUrl(cookies, account->url());
|
||||
jar->blockSignals(false);
|
||||
}
|
||||
|
||||
|
||||
} // ns Mirall
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <QMap>
|
||||
#include <QNetworkCookie>
|
||||
#include <QUrl>
|
||||
#include <QPointer>
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
@@ -25,6 +26,8 @@ namespace QKeychain {
|
||||
class Job;
|
||||
}
|
||||
|
||||
class QAuthenticator;
|
||||
|
||||
namespace Mirall
|
||||
{
|
||||
|
||||
@@ -36,7 +39,6 @@ Q_OBJECT
|
||||
|
||||
public:
|
||||
ShibbolethCredentials();
|
||||
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
|
||||
|
||||
void syncContextPreInit(CSYNC* ctx);
|
||||
void syncContextPreStart(CSYNC* ctx);
|
||||
@@ -50,16 +52,19 @@ public:
|
||||
void persist(Account *account);
|
||||
void invalidateToken(Account *account);
|
||||
|
||||
QNetworkCookie cookie() const;
|
||||
|
||||
void showLoginWindow(Account*);
|
||||
|
||||
static QList<QNetworkCookie> accountCookies(Account*);
|
||||
static QNetworkCookie findShibCookie(Account*, QList<QNetworkCookie> cookies = QList<QNetworkCookie>());
|
||||
static QByteArray shibCookieName();
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidateAndFetch(Account *account);
|
||||
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onShibbolethCookieReceived(const QNetworkCookie& cookie, Account*);
|
||||
void slotBrowserHidden();
|
||||
void onShibbolethCookieReceived(const QNetworkCookie&, Account*);
|
||||
void slotBrowserRejected();
|
||||
void onFetched();
|
||||
void slotReadJobDone(QKeychain::Job*);
|
||||
void slotInvalidateAndFetchInvalidateDone(QKeychain::Job*);
|
||||
@@ -73,15 +78,16 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
void storeShibCookie(const QNetworkCookie &cookie, Account *account);
|
||||
void removeShibCookie(Account *account);
|
||||
void addToCookieJar(const QNetworkCookie &cookie);
|
||||
QUrl _url;
|
||||
QByteArray prepareCookieData() const;
|
||||
void disposeBrowser();
|
||||
|
||||
QNetworkCookie _shibCookie;
|
||||
bool _ready;
|
||||
bool _stillValid;
|
||||
ShibbolethWebView* _browser;
|
||||
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
|
||||
bool _fetchJobInProgress;
|
||||
QPointer<ShibbolethWebView> _browser;
|
||||
QNetworkCookie _shibCookie;
|
||||
QString _user;
|
||||
};
|
||||
|
||||
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -11,8 +12,15 @@
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "mirall/application.h"
|
||||
#include "mirall/theme.h"
|
||||
#include "mirall/utility.h"
|
||||
@@ -51,6 +59,20 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check a environment variable for core dumps
|
||||
#ifdef Q_OS_UNIX
|
||||
if( !qgetenv("OWNCLOUD_CORE_DUMP").isEmpty() ) {
|
||||
struct rlimit core_limit;
|
||||
core_limit.rlim_cur = RLIM_INFINITY;
|
||||
core_limit.rlim_max = RLIM_INFINITY;
|
||||
|
||||
if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
|
||||
fprintf(stderr, "Unable to set core dump limit\n");
|
||||
} else {
|
||||
qDebug() << "Core dumps enabled";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// if handleStartup returns true, main()
|
||||
// needs to terminate here, e.g. because
|
||||
// the updater is triggered
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
*/
|
||||
|
||||
#include "mirall/account.h"
|
||||
#include "mirall/cookiejar.h"
|
||||
#include "mirall/theme.h"
|
||||
#include "mirall/networkjobs.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/quotainfo.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "creds/credentialsfactory.h"
|
||||
@@ -75,6 +77,8 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
|
||||
|
||||
Account::~Account()
|
||||
{
|
||||
delete _credentials;
|
||||
delete _am;
|
||||
}
|
||||
|
||||
void Account::save()
|
||||
@@ -161,7 +165,11 @@ AbstractCredentials *Account::credentials() const
|
||||
void Account::setCredentials(AbstractCredentials *cred)
|
||||
{
|
||||
// set active credential manager
|
||||
QNetworkCookieJar *jar = 0;
|
||||
if (_am) {
|
||||
jar = _am->cookieJar();
|
||||
jar->setParent(0);
|
||||
|
||||
_am->deleteLater();
|
||||
}
|
||||
|
||||
@@ -170,6 +178,9 @@ void Account::setCredentials(AbstractCredentials *cred)
|
||||
}
|
||||
_credentials = cred;
|
||||
_am = _credentials->getQNAM();
|
||||
if (jar) {
|
||||
_am->setCookieJar(jar);
|
||||
}
|
||||
connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
|
||||
SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
|
||||
}
|
||||
@@ -186,7 +197,12 @@ QList<QNetworkCookie> Account::lastAuthCookies() const
|
||||
|
||||
void Account::clearCookieJar()
|
||||
{
|
||||
_am->setCookieJar(new QNetworkCookieJar);
|
||||
_am->setCookieJar(new CookieJar);
|
||||
}
|
||||
|
||||
QNetworkAccessManager *Account::networkAccessManager()
|
||||
{
|
||||
return _am;
|
||||
}
|
||||
|
||||
QNetworkReply *Account::headRequest(const QString &relPath)
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Mirall {
|
||||
class AbstractCredentials;
|
||||
class Account;
|
||||
class QuotaInfo;
|
||||
class MirallAccessManager;
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT AccountManager : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -143,6 +144,8 @@ public:
|
||||
|
||||
void clearCookieJar();
|
||||
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
||||
QuotaInfo *quotaInfo();
|
||||
signals:
|
||||
void stateChanged(int state);
|
||||
|
||||
@@ -114,7 +114,6 @@ AccountSettings::AccountSettings(QWidget *parent) :
|
||||
connect(FolderMan::instance(), SIGNAL(folderListLoaded(Folder::Map)),
|
||||
this, SLOT(setFolderList(Folder::Map)));
|
||||
setFolderList(FolderMan::instance()->map());
|
||||
|
||||
}
|
||||
|
||||
void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccount)
|
||||
@@ -140,28 +139,28 @@ void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccoun
|
||||
|
||||
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
|
||||
{
|
||||
bool state = indx.isValid();
|
||||
bool isValid = indx.isValid();
|
||||
|
||||
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
|
||||
|
||||
ui->_buttonRemove->setEnabled(state);
|
||||
ui->_buttonRemove->setEnabled(isValid);
|
||||
if( Theme::instance()->singleSyncFolder() ) {
|
||||
// only one folder synced folder allowed.
|
||||
ui->_buttonAdd->setVisible(!haveFolders);
|
||||
} else {
|
||||
ui->_buttonAdd->setVisible(true);
|
||||
ui->_buttonAdd->setEnabled( true );
|
||||
}
|
||||
ui->_buttonEnable->setEnabled( state );
|
||||
ui->_buttonAdd->setEnabled(_account && _account->state() == Account::Connected);
|
||||
ui->_buttonEnable->setEnabled( isValid );
|
||||
|
||||
if ( state ) {
|
||||
if ( isValid ) {
|
||||
bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
|
||||
if ( folderEnabled ) {
|
||||
ui->_buttonEnable->setText( tr( "Pause" ) );
|
||||
} else {
|
||||
ui->_buttonEnable->setText( tr( "Resume" ) );
|
||||
}
|
||||
ui->_buttonEnable->setEnabled(_account && _account->state() == Account::Connected);
|
||||
ui->_buttonEnable->setEnabled( _account && _account->state() == Account::Connected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,8 +172,6 @@ void AccountSettings::slotAddFolder()
|
||||
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()));
|
||||
@@ -269,6 +266,10 @@ void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
|
||||
// if the folder was disabled before, set the sync icon
|
||||
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
|
||||
} // we keep the previous icon for the SyncPrepare state.
|
||||
} else if( status == SyncResult::Undefined ) {
|
||||
// startup, the sync was never done.
|
||||
qDebug() << "XXX FIRST time sync, setting icon to sync running!";
|
||||
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
|
||||
} else {
|
||||
// kepp the previous icon for the prepare phase.
|
||||
if( status == SyncResult::Problem) {
|
||||
@@ -361,7 +362,7 @@ void AccountSettings::slotResetCurrentFolder()
|
||||
if( ret == QMessageBox::Yes ) {
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
Folder *f = folderMan->folder(alias);
|
||||
f->slotTerminateSync(true);
|
||||
f->slotTerminateSync();
|
||||
f->wipe();
|
||||
folderMan->slotScheduleAllFolders();
|
||||
}
|
||||
@@ -415,28 +416,6 @@ void AccountSettings::setFolderList( const Folder::Map &folders )
|
||||
|
||||
}
|
||||
|
||||
// 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_WIN
|
||||
// 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();
|
||||
@@ -453,7 +432,11 @@ void AccountSettings::slotEnableCurrentFolder()
|
||||
|
||||
// this sets the folder status to disabled but does not interrupt it.
|
||||
Folder *f = folderMan->folder( alias );
|
||||
if( f && folderEnabled ) {
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( folderEnabled ) {
|
||||
// check if a sync is still running and if so, ask if we should terminate.
|
||||
if( f->isBusy() ) { // its still running
|
||||
#if defined(Q_OS_MAC)
|
||||
@@ -478,7 +461,7 @@ void AccountSettings::slotEnableCurrentFolder()
|
||||
// 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 ) {
|
||||
f->slotTerminateSync(false);
|
||||
f->slotTerminateSync();
|
||||
}
|
||||
|
||||
folderMan->slotEnableFolder( alias, !folderEnabled );
|
||||
@@ -633,8 +616,9 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
|
||||
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
|
||||
|
||||
int overallPercent = 0;
|
||||
if( progress._totalSize > 0 ) {
|
||||
overallPercent = qRound(double(completedSize)/double(progress._totalSize) * 100.0);
|
||||
if( progress._totalFileCount > 0 ) {
|
||||
// Add one 'byte' for each files so the percentage is moving when deleting or renaming files
|
||||
overallPercent = qRound(double(completedSize + progress._completedFileCount)/double(progress._totalSize + progress._totalFileCount) * 100.0);
|
||||
}
|
||||
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
|
||||
}
|
||||
@@ -739,7 +723,7 @@ void AccountSettings::slotAccountStateChanged(int state)
|
||||
ui->sslButton->updateAccountInfo(_account);
|
||||
QUrl safeUrl(_account->url());
|
||||
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
|
||||
ui->_buttonAdd->setEnabled(state == Account::Connected);
|
||||
slotButtonsSetEnabled();
|
||||
if (state == Account::Connected) {
|
||||
QString user;
|
||||
if (AbstractCredentials *cred = _account->credentials()) {
|
||||
|
||||
@@ -60,7 +60,6 @@ public slots:
|
||||
void slotOpenOC();
|
||||
void slotUpdateFolderState( Folder* );
|
||||
void slotDoubleClicked( const QModelIndex& );
|
||||
void slotFolderOpenAction( const QString& );
|
||||
void slotSetProgress(const QString& folder, const Progress::Info& progress);
|
||||
void slotButtonsSetEnabled();
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
||||
class QSocket;
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
namespace {
|
||||
@@ -64,14 +66,12 @@ static const char optionsC[] =
|
||||
|
||||
QString applicationTrPath()
|
||||
{
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(Q_OS_WIN)
|
||||
return QApplication::applicationDirPath();
|
||||
#elif defined(Q_OS_MAC)
|
||||
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
|
||||
#elif defined(Q_OS_UNIX)
|
||||
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ QString applicationTrPath()
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
Application::Application(int &argc, char **argv) :
|
||||
SharedTools::QtSingleApplication(argc, argv),
|
||||
SharedTools::QtSingleApplication(Theme::instance()->appName() ,argc, argv),
|
||||
_gui(0),
|
||||
_theme(Theme::instance()),
|
||||
_helpOnly(false),
|
||||
@@ -99,14 +99,13 @@ Application::Application(int &argc, char **argv) :
|
||||
//no need to waste time;
|
||||
if ( _helpOnly ) return;
|
||||
|
||||
initialize();
|
||||
if (isRunning())
|
||||
return;
|
||||
|
||||
setupLogging();
|
||||
setupTranslations();
|
||||
|
||||
connect( this, SIGNAL(messageReceived(QString)), SLOT(slotParseOptions(QString)));
|
||||
connect( this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseOptions(QString, QObject*)));
|
||||
|
||||
Account *account = Account::restore();
|
||||
if (account) {
|
||||
@@ -159,6 +158,7 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
delete AccountManager::instance()->account();
|
||||
// qDebug() << "* Mirall shutdown";
|
||||
}
|
||||
|
||||
@@ -245,6 +245,8 @@ void Application::slotCheckConnection()
|
||||
} else {
|
||||
// let gui open the setup wizard
|
||||
_gui->slotOpenSettingsDialog( true );
|
||||
|
||||
_checkConnectionTimer.stop(); // don't popup the wizard on interval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +325,7 @@ void Application::slotownCloudWizardDone( int res )
|
||||
}
|
||||
folderMan->setSyncEnabled( true );
|
||||
if( res == QDialog::Accepted ) {
|
||||
_checkConnectionTimer.start();
|
||||
slotCheckConnection();
|
||||
}
|
||||
|
||||
@@ -350,7 +353,7 @@ void Application::slotUseMonoIconsChanged(bool)
|
||||
_gui->slotComputeOverallSyncStatus();
|
||||
}
|
||||
|
||||
void Application::slotParseOptions(const QString &opts)
|
||||
void Application::slotParseOptions(const QString &opts, QObject*)
|
||||
{
|
||||
QStringList options = opts.split(QLatin1Char('|'));
|
||||
parseOptions(options);
|
||||
|
||||
@@ -28,9 +28,11 @@
|
||||
#include "mirall/connectionvalidator.h"
|
||||
#include "mirall/progressdispatcher.h"
|
||||
#include "mirall/clientproxy.h"
|
||||
#include "mirall/folderman.h"
|
||||
|
||||
class QMessageBox;
|
||||
class QSystemTrayIcon;
|
||||
class QSocket;
|
||||
|
||||
namespace Mirall {
|
||||
class Theme;
|
||||
@@ -69,7 +71,7 @@ signals:
|
||||
void folderStateChanged(Folder*);
|
||||
|
||||
protected slots:
|
||||
void slotParseOptions( const QString& );
|
||||
void slotParseOptions( const QString&, QObject* );
|
||||
void slotCheckConnection();
|
||||
void slotConnectionValidatorResult(ConnectionValidator::Status);
|
||||
void slotStartUpdateDetector();
|
||||
@@ -106,6 +108,8 @@ private:
|
||||
|
||||
QTimer _checkConnectionTimer;
|
||||
|
||||
FolderMan folderManager;
|
||||
|
||||
friend class ownCloudGui; // for _startupNetworkError
|
||||
};
|
||||
|
||||
|
||||
155
src/mirall/cookiejar.cpp
Normal file
155
src/mirall/cookiejar.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 "cookiejar.h"
|
||||
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
namespace {
|
||||
const unsigned int JAR_VERSION = 23;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
|
||||
{
|
||||
stream << JAR_VERSION;
|
||||
stream << quint32(list.size());
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
stream << list.at(i).toRawForm();
|
||||
return stream;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
|
||||
{
|
||||
list.clear();
|
||||
|
||||
quint32 version;
|
||||
stream >> version;
|
||||
|
||||
if (version != JAR_VERSION)
|
||||
return stream;
|
||||
|
||||
quint32 count;
|
||||
stream >> count;
|
||||
for(quint32 i = 0; i < count; ++i)
|
||||
{
|
||||
QByteArray value;
|
||||
stream >> value;
|
||||
QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
|
||||
if (newCookies.count() == 0 && value.length() != 0) {
|
||||
qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
|
||||
}
|
||||
for (int j = 0; j < newCookies.count(); ++j)
|
||||
list.append(newCookies.at(j));
|
||||
if (stream.atEnd())
|
||||
break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
CookieJar::CookieJar(QObject *parent) :
|
||||
QNetworkCookieJar(parent)
|
||||
{
|
||||
restore();
|
||||
}
|
||||
|
||||
CookieJar::~CookieJar()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
||||
{
|
||||
if (QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) {
|
||||
Q_EMIT newCookiesForUrl(cookieList, url);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
|
||||
{
|
||||
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
|
||||
// qDebug() << url << "requests:" << cookies;
|
||||
return cookies;
|
||||
}
|
||||
|
||||
bool CookieJar::deleteCookie(const QNetworkCookie &delCookie)
|
||||
{
|
||||
QList<QNetworkCookie> cookies = allCookies();
|
||||
bool removeSucceeded = false;
|
||||
foreach(const QNetworkCookie &cookie, cookies) {
|
||||
// ### cookies are not identical in attriutes, why?
|
||||
if (cookie.name() == delCookie.name()) {
|
||||
cookies.removeOne(cookie);
|
||||
removeSucceeded = true;
|
||||
}
|
||||
}
|
||||
setAllCookies(cookies);
|
||||
return removeSucceeded;
|
||||
}
|
||||
|
||||
void CookieJar::clearSessionCookies()
|
||||
{
|
||||
setAllCookies(removeExpired(allCookies()));
|
||||
}
|
||||
|
||||
|
||||
void CookieJar::save()
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
qDebug() << storagePath();
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream stream(&file);
|
||||
stream << allCookies();
|
||||
file.close();
|
||||
}
|
||||
|
||||
void CookieJar::restore()
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QDataStream stream(&file);
|
||||
QList<QNetworkCookie> list;
|
||||
stream >> list;
|
||||
setAllCookies(removeExpired(list));
|
||||
file.close();
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cookies)
|
||||
{
|
||||
QList<QNetworkCookie> updatedList;
|
||||
foreach(const QNetworkCookie &cookie, cookies) {
|
||||
if (cookie.expirationDate() > QDateTime::currentDateTime() && !cookie.isSessionCookie()) {
|
||||
updatedList << cookie;
|
||||
}
|
||||
}
|
||||
return updatedList;
|
||||
}
|
||||
|
||||
QString CookieJar::storagePath() const
|
||||
{
|
||||
MirallConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies.db";
|
||||
}
|
||||
|
||||
} // namespace Mirall
|
||||
47
src/mirall/cookiejar.h
Normal file
47
src/mirall/cookiejar.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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_COOKIEJAR_H
|
||||
#define MIRALL_COOKIEJAR_H
|
||||
|
||||
#include <QNetworkCookieJar>
|
||||
|
||||
#include "owncloudlib.h"
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT CookieJar : public QNetworkCookieJar
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CookieJar(QObject *parent = 0);
|
||||
~CookieJar();
|
||||
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
|
||||
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
|
||||
|
||||
virtual bool deleteCookie(const QNetworkCookie & cookie);
|
||||
void clearSessionCookies();
|
||||
|
||||
signals:
|
||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
private:
|
||||
void save();
|
||||
void restore();
|
||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||
QString storagePath() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Mirall
|
||||
|
||||
#endif // MIRALL_COOKIEJAR_H
|
||||
@@ -91,10 +91,29 @@ Folder::Folder(const QString &alias, const QString &path, const QString& secondP
|
||||
|
||||
bool Folder::init()
|
||||
{
|
||||
QString url = Utility::toCSyncScheme(remoteUrl().toString());
|
||||
Account *account = AccountManager::instance()->account();
|
||||
if (!account) {
|
||||
// Normaly this should not happen, but it could be that there is something
|
||||
// wrong with the config and it is better not to crash.
|
||||
qWarning() << "WRN: No account configured, can't sync";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to reconstruct the url because the path need to be fully decoded, as csync will re-encode the path:
|
||||
// Remember that csync will just append the filename to the path and pass it to the vio plugin.
|
||||
// csync_owncloud will then re-encode everything.
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
QUrl url = remoteUrl();
|
||||
QString url_string = url.scheme() + QLatin1String("://") + url.authority(QUrl::EncodeDelimiters) + url.path(QUrl::FullyDecoded);
|
||||
#else
|
||||
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a provlem when parsing the path from QUrl::setPath
|
||||
QString url_string = remoteUrl().toString();
|
||||
#endif
|
||||
url_string = Utility::toCSyncScheme(url_string);
|
||||
|
||||
QString localpath = path();
|
||||
|
||||
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
|
||||
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url_string.toUtf8().data() ) < 0 ) {
|
||||
qDebug() << "Unable to create csync-context!";
|
||||
slotSyncError(tr("Unable to create csync-context"));
|
||||
_csync_ctx = 0;
|
||||
@@ -301,8 +320,7 @@ void Folder::bubbleUpSyncResult()
|
||||
|
||||
SyncRunFileLog syncFileLog;
|
||||
|
||||
syncFileLog.start(path(), _stopWatch );
|
||||
_stopWatch.reset();
|
||||
syncFileLog.start(path(), _engine ? _engine->stopWatch() : Utility::StopWatch() );
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
@@ -467,7 +485,7 @@ void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
void Folder::slotTerminateSync(bool block)
|
||||
void Folder::slotTerminateSync()
|
||||
{
|
||||
qDebug() << "folder " << alias() << " Terminating!";
|
||||
|
||||
@@ -477,14 +495,10 @@ void Folder::slotTerminateSync(bool block)
|
||||
// Do not display an error message, user knows his own actions.
|
||||
// _errors.append( tr("The CSync thread terminated.") );
|
||||
// _csyncError = true;
|
||||
if (!block) {
|
||||
setSyncState(SyncResult::SyncAbortRequested);
|
||||
return;
|
||||
}
|
||||
|
||||
slotSyncFinished();
|
||||
setSyncEnabled(false);
|
||||
setSyncState(SyncResult::SyncAbortRequested);
|
||||
return;
|
||||
}
|
||||
setSyncEnabled(false);
|
||||
}
|
||||
|
||||
// This removes the csync File database
|
||||
@@ -630,7 +644,6 @@ void Folder::slotSyncFinished()
|
||||
qDebug() << "-> CSync Finished slot with error " << _csyncError << "warn count" << _syncResult.warnCount();
|
||||
|
||||
bubbleUpSyncResult();
|
||||
_stopWatch = _engine->stopWatch();
|
||||
|
||||
_engine.reset(0);
|
||||
// _watcher->setEventsEnabledDelayed(2000);
|
||||
@@ -653,9 +666,24 @@ void Folder::slotSyncFinished()
|
||||
}
|
||||
|
||||
emit syncStateChange();
|
||||
|
||||
// The syncFinished result that is to be triggered here makes the folderman
|
||||
// clearing the current running sync folder marker.
|
||||
// Lets wait a bit to do that because, as long as this marker is not cleared,
|
||||
// file system change notifications are ignored for that folder. And it takes
|
||||
// some time under certain conditions to make the file system notifications
|
||||
// all come in.
|
||||
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
|
||||
|
||||
}
|
||||
|
||||
void Folder::slotEmitFinishedDelayed()
|
||||
{
|
||||
emit syncFinished( _syncResult );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// the progress comes without a folder and the valid path set. Add that here
|
||||
// and hand the result over to the progress dispatcher.
|
||||
void Folder::slotTransmissionProgress(const Progress::Info &pi)
|
||||
@@ -695,6 +723,9 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
|
||||
*cancel = msgBox.clickedButton() == keepBtn;
|
||||
if (*cancel) {
|
||||
wipe();
|
||||
// speed up next sync
|
||||
_lastEtag = QString();
|
||||
QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "mirall/progressdispatcher.h"
|
||||
#include "mirall/syncjournaldb.h"
|
||||
#include "mirall/clientproxy.h"
|
||||
#include "mirall/utility.h"
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
@@ -149,10 +148,8 @@ public slots:
|
||||
|
||||
/**
|
||||
* terminate the current sync run
|
||||
*
|
||||
* If block is true, this will block synchroniously for the sync thread to finish.
|
||||
*/
|
||||
void slotTerminateSync(bool block);
|
||||
void slotTerminateSync();
|
||||
|
||||
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||
|
||||
@@ -184,9 +181,12 @@ private slots:
|
||||
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& );
|
||||
|
||||
void slotEmitFinishedDelayed();
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
||||
|
||||
void setIgnoredFiles();
|
||||
|
||||
void bubbleUpSyncResult();
|
||||
@@ -200,7 +200,6 @@ private:
|
||||
QString _remotePath;
|
||||
QString _alias;
|
||||
QString _configFile;
|
||||
QFileSystemWatcher *_pathWatcher;
|
||||
bool _enabled;
|
||||
SyncResult _syncResult;
|
||||
QScopedPointer<SyncEngine> _engine;
|
||||
@@ -217,8 +216,6 @@ private:
|
||||
|
||||
ClientProxy _clientProxy;
|
||||
|
||||
Utility::StopWatch _stopWatch;
|
||||
|
||||
CSYNC *_csync_ctx;
|
||||
};
|
||||
|
||||
|
||||
@@ -41,13 +41,6 @@ FolderMan::FolderMan(QObject *parent) :
|
||||
QObject(parent),
|
||||
_syncEnabled( true )
|
||||
{
|
||||
// if QDir::mkpath would not be so stupid, I would not need to have this
|
||||
// duplication of folderConfigPath() here
|
||||
MirallConfigFile cfg;
|
||||
QDir storageDir(cfg.configPath());
|
||||
storageDir.mkpath(QLatin1String("folders"));
|
||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||
|
||||
_folderChangeSignalMapper = new QSignalMapper(this);
|
||||
connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)),
|
||||
this, SIGNAL(folderSyncStateChange(const QString &)));
|
||||
@@ -55,15 +48,14 @@ FolderMan::FolderMan(QObject *parent) :
|
||||
_folderWatcherSignalMapper = new QSignalMapper(this);
|
||||
connect(_folderWatcherSignalMapper, SIGNAL(mapped(const QString&)),
|
||||
this, SLOT(slotScheduleSync(const QString&)));
|
||||
|
||||
ne_sock_init();
|
||||
Q_ASSERT(!_instance);
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
FolderMan *FolderMan::instance()
|
||||
{
|
||||
if(!_instance) {
|
||||
_instance = new FolderMan;
|
||||
ne_sock_init();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
@@ -71,6 +63,7 @@ FolderMan::~FolderMan()
|
||||
{
|
||||
qDeleteAll(_folderMap);
|
||||
ne_sock_exit();
|
||||
_instance = 0;
|
||||
}
|
||||
|
||||
Mirall::Folder::Map FolderMan::map()
|
||||
@@ -144,6 +137,11 @@ int FolderMan::setupFolders()
|
||||
|
||||
unloadAllFolders();
|
||||
|
||||
MirallConfigFile cfg;
|
||||
QDir storageDir(cfg.configPath());
|
||||
storageDir.mkpath(QLatin1String("folders"));
|
||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||
|
||||
QDir dir( _folderConfigPath );
|
||||
//We need to include hidden files just in case the alias starts with '.'
|
||||
dir.setFilter(QDir::Files | QDir::Hidden);
|
||||
@@ -301,6 +299,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
||||
qDebug() << "Adding folder to Folder Map " << folder;
|
||||
_folderMap[alias] = folder;
|
||||
if (paused) {
|
||||
folder->setSyncEnabled(!paused);
|
||||
_disabledFolders.insert(folder);
|
||||
}
|
||||
|
||||
@@ -353,9 +352,10 @@ void FolderMan::terminateSyncProcess( const QString& alias )
|
||||
if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) {
|
||||
Folder *f = _folderMap[folderAlias];
|
||||
if( f ) {
|
||||
f->slotTerminateSync(true);
|
||||
if(_currentSyncFolder == folderAlias )
|
||||
f->slotTerminateSync();
|
||||
if(_currentSyncFolder == folderAlias ) {
|
||||
_currentSyncFolder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,13 @@ class SyncResult;
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
class Application;
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT FolderMan : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static FolderMan* instance();
|
||||
~FolderMan();
|
||||
|
||||
int setupFolders();
|
||||
|
||||
@@ -144,10 +145,10 @@ private:
|
||||
QQueue<QString> _scheduleQueue;
|
||||
QMap<QString, FolderWatcher*> _folderWatchers;
|
||||
|
||||
|
||||
explicit FolderMan(QObject *parent = 0);
|
||||
static FolderMan *_instance;
|
||||
|
||||
explicit FolderMan(QObject *parent = 0);
|
||||
~FolderMan();
|
||||
friend class Mirall::Application;
|
||||
};
|
||||
|
||||
} // namespace Mirall
|
||||
|
||||
@@ -56,9 +56,6 @@ class FolderStatusDelegate : public QStyledItemDelegate
|
||||
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index );
|
||||
|
||||
private:
|
||||
bool _addProgressSpace;
|
||||
};
|
||||
|
||||
} // namespace Mirall
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "mirall/folderwatcher_win.h"
|
||||
#elif defined(Q_OS_MAC)
|
||||
#include "mirall/folderwatcher_mac.h"
|
||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
#elif defined(Q_OS_UNIX)
|
||||
#include "mirall/folderwatcher_linux.h"
|
||||
#endif
|
||||
|
||||
@@ -115,7 +115,7 @@ void FolderWatcher::changeDetected( const QString& path )
|
||||
|
||||
void FolderWatcher::changeDetected( const QStringList& paths )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << paths;
|
||||
// qDebug() << Q_FUNC_INFO << paths;
|
||||
|
||||
// TODO: this shortcut doesn't look very reliable:
|
||||
// - why is the timeout only 1 second?
|
||||
|
||||
@@ -104,7 +104,7 @@ bool FolderWizardLocalPath::isComplete() const
|
||||
}
|
||||
|
||||
// check if the local directory isn't used yet in another ownCloud sync
|
||||
Folder::Map map = _folderMap;
|
||||
Folder::Map map = FolderMan::instance()->map();
|
||||
|
||||
if( isOk ) {
|
||||
Folder::Map::const_iterator i = map.constBegin();
|
||||
@@ -136,7 +136,7 @@ bool FolderWizardLocalPath::isComplete() const
|
||||
QString absCleanUserFolder = QDir::cleanPath(QDir(userInput).canonicalPath())+'/';
|
||||
if( isOk && QDir::cleanPath(folderDir).startsWith(absCleanUserFolder) ) {
|
||||
qDebug() << "A already configured folder is child of the current selected";
|
||||
warnStrings.append( tr("The selected folder is a symbolic link. An already configured"
|
||||
warnStrings.append( tr("The selected folder is a symbolic link. An already configured "
|
||||
"folder is contained in the folder this link is pointing to."));
|
||||
isOk = false;
|
||||
}
|
||||
@@ -170,8 +170,8 @@ bool FolderWizardLocalPath::isComplete() const
|
||||
bool goon = true;
|
||||
while( goon && i != map.constEnd() ) {
|
||||
Folder *f = i.value();
|
||||
qDebug() << "Checking local alias: " << f->alias();
|
||||
if( f ) {
|
||||
qDebug() << "Checking local alias: " << f->alias();
|
||||
if( f->alias() == alias ) {
|
||||
warnStrings.append( tr("The alias <i>%1</i> is already in use. Please pick another alias.").arg(alias) );
|
||||
isOk = false;
|
||||
@@ -224,7 +224,10 @@ void FolderWizardLocalPath::slotChooseLocalFolder()
|
||||
// =================================================================================
|
||||
FolderWizardRemotePath::FolderWizardRemotePath()
|
||||
: FormatWarningsWizardPage()
|
||||
, _ownCloudDirCheck(0)
|
||||
, _dirChecked(false)
|
||||
,_warnWasVisible(false)
|
||||
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
_ui.warnFrame->hide();
|
||||
@@ -374,7 +377,7 @@ bool FolderWizardRemotePath::isComplete() const
|
||||
}
|
||||
wizard()->setProperty("targetPath", dir);
|
||||
|
||||
Folder::Map map = _folderMap;
|
||||
Folder::Map map = FolderMan::instance()->map();
|
||||
Folder::Map::const_iterator i = map.constBegin();
|
||||
for(i = map.constBegin();i != map.constEnd(); i++ ) {
|
||||
Folder *f = static_cast<Folder*>(i.value());
|
||||
@@ -448,13 +451,6 @@ FolderWizard::~FolderWizard()
|
||||
{
|
||||
}
|
||||
|
||||
void FolderWizard::setFolderMap( const Folder::Map& fm)
|
||||
{
|
||||
_folderWizardSourcePage->setFolderMap( fm );
|
||||
if (!Theme::instance()->singleSyncFolder()) {
|
||||
_folderWizardTargetPage->setFolderMap( fm );
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
@@ -73,8 +73,6 @@ public:
|
||||
virtual void initializePage();
|
||||
virtual void cleanupPage();
|
||||
|
||||
void setFolderMap( const Folder::Map &fm ) { _folderMap = fm; }
|
||||
|
||||
protected slots:
|
||||
|
||||
void showWarn( const QString& = QString() ) const;
|
||||
@@ -91,7 +89,7 @@ private:
|
||||
ownCloudInfo *_ownCloudDirCheck;
|
||||
bool _dirChecked;
|
||||
bool _warnWasVisible;
|
||||
Folder::Map _folderMap;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -109,7 +107,6 @@ public:
|
||||
|
||||
FolderWizard(QWidget *parent = 0);
|
||||
~FolderWizard();
|
||||
void setFolderMap( const Folder::Map &map );
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ static void mirallLogCatcher(QtMsgType type, const char *msg)
|
||||
// qDebug() exports to local8Bit, which is not always UTF-8
|
||||
Logger::instance()->mirallLog( QString::fromLocal8Bit(msg) );
|
||||
}
|
||||
static void qInstallMessageHandler(QtMsgHandler h) {
|
||||
qInstallMsgHandler(h);
|
||||
}
|
||||
#else
|
||||
static void mirallLogCatcher(QtMsgType, const QMessageLogContext &ctx, const QString &message) {
|
||||
Q_UNUSED(ctx);
|
||||
@@ -38,35 +41,23 @@ static void mirallLogCatcher(QtMsgType, const QMessageLogContext &ctx, const QSt
|
||||
}
|
||||
#endif
|
||||
|
||||
Logger* Logger::_instance=0;
|
||||
|
||||
Logger::Logger( QObject* parent)
|
||||
: QObject(parent),
|
||||
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
|
||||
{
|
||||
}
|
||||
|
||||
Logger *Logger::instance()
|
||||
{
|
||||
if( !Logger::_instance ) {
|
||||
Logger::_instance = new Logger;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
qInstallMsgHandler( mirallLogCatcher );
|
||||
#else
|
||||
qInstallMessageHandler(mirallLogCatcher);
|
||||
#endif
|
||||
}
|
||||
return Logger::_instance;
|
||||
static Logger log;
|
||||
return &log;
|
||||
}
|
||||
|
||||
void Logger::destroy()
|
||||
Logger::Logger( QObject* parent) : QObject(parent),
|
||||
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
|
||||
{
|
||||
if( Logger::_instance ) {
|
||||
delete Logger::_instance;
|
||||
Logger::_instance = 0;
|
||||
}
|
||||
qInstallMessageHandler(mirallLogCatcher);
|
||||
}
|
||||
|
||||
Logger::~Logger() {
|
||||
qInstallMessageHandler(0);
|
||||
}
|
||||
|
||||
|
||||
void Logger::postGuiLog(const QString &title, const QString &message)
|
||||
{
|
||||
emit guiLog(title, message);
|
||||
|
||||
@@ -41,6 +41,7 @@ class OWNCLOUDSYNC_EXPORT Logger : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
void log(Log log);
|
||||
|
||||
static void csyncLog( const QString& message );
|
||||
@@ -49,7 +50,6 @@ public:
|
||||
const QList<Log>& logs() const {return _logs;}
|
||||
|
||||
static Logger* instance();
|
||||
static void destroy();
|
||||
|
||||
void postGuiLog(const QString& title, const QString& message);
|
||||
void postOptionalGuiLog(const QString& title, const QString& message);
|
||||
@@ -69,14 +69,12 @@ signals:
|
||||
public slots:
|
||||
void enterNextLogFile();
|
||||
|
||||
protected:
|
||||
private:
|
||||
Logger(QObject* parent=0);
|
||||
~Logger();
|
||||
QList<Log> _logs;
|
||||
bool _showTime;
|
||||
bool _doLogging;
|
||||
|
||||
static Logger* _instance;
|
||||
|
||||
QFile _logFile;
|
||||
bool _doFileFlush;
|
||||
int _logExpire;
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkProxy>
|
||||
#include <QAuthenticator>
|
||||
#include <QSslConfiguration>
|
||||
|
||||
#include "mirall/cookiejar.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/utility.h"
|
||||
|
||||
@@ -30,6 +32,7 @@ MirallAccessManager::MirallAccessManager(QObject* parent)
|
||||
proxy.setHostName(" ");
|
||||
setProxy(proxy);
|
||||
#endif
|
||||
setCookieJar(new CookieJar);
|
||||
QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
|
||||
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ static const char monoIconsC[] = "monoIcons";
|
||||
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
|
||||
static const char skipUpdateCheckC[] = "skipUpdateCheck";
|
||||
static const char geometryC[] = "geometry";
|
||||
static const char timeoutC[] = "timeout";
|
||||
|
||||
static const char proxyHostC[] = "Proxy/host";
|
||||
static const char proxyTypeC[] = "Proxy/type";
|
||||
@@ -103,6 +104,12 @@ bool MirallConfigFile::optionalDesktopNotifications() const
|
||||
return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool();
|
||||
}
|
||||
|
||||
int MirallConfigFile::timeout() const
|
||||
{
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min
|
||||
}
|
||||
|
||||
void MirallConfigFile::setOptionalDesktopNotifications(bool show)
|
||||
{
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
bool optionalDesktopNotifications() const;
|
||||
void setOptionalDesktopNotifications(bool show);
|
||||
|
||||
int timeout() const;
|
||||
|
||||
void saveGeometry(QWidget *w);
|
||||
void restoreGeometry(QWidget *w);
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ public:
|
||||
void setReply(QNetworkReply *reply);
|
||||
QNetworkReply* reply() const { return _reply; }
|
||||
|
||||
void setTimeout(qint64 msec);
|
||||
void resetTimeout();
|
||||
|
||||
void setIgnoreCredentialFailure(bool ignore);
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
@@ -72,6 +70,9 @@ public:
|
||||
QString responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
public slots:
|
||||
void setTimeout(qint64 msec);
|
||||
void resetTimeout();
|
||||
signals:
|
||||
void networkError(QNetworkReply *reply);
|
||||
protected:
|
||||
@@ -100,7 +101,7 @@ private slots:
|
||||
private:
|
||||
QNetworkReply* addTimer(QNetworkReply *reply);
|
||||
bool _ignoreCredentialFailure;
|
||||
QNetworkReply *_reply;
|
||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||
Account *_account;
|
||||
QString _path;
|
||||
QTimer _timer;
|
||||
|
||||
@@ -326,10 +326,9 @@ void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QStrin
|
||||
void ownCloudGui::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") );
|
||||
qDebug() << "opening local url " << f->path();
|
||||
QUrl url = QUrl::fromLocalFile(f->path());
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// work around a bug in QDesktopServices on Win32, see i-net
|
||||
|
||||
@@ -19,9 +19,16 @@
|
||||
#include "propagator_qnam.h"
|
||||
#include "propagatorjobs.h"
|
||||
#include "propagator_legacy.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/utility.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include <QStack>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
@@ -45,11 +52,6 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
||||
if( _item._httpErrorCode == 403 ||_item._httpErrorCode == 413 || _item._httpErrorCode == 415 ) {
|
||||
qDebug() << "Fatal Error condition" << _item._httpErrorCode << ", forbid retry!";
|
||||
retries = -1;
|
||||
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
|
||||
} else if (_item._httpErrorCode / 100 == 5) {
|
||||
// In this configuration, never blacklist error 5xx
|
||||
qDebug() << "Do not blacklist error " << _item._httpErrorCode;
|
||||
#endif
|
||||
} else {
|
||||
static QAtomicInt defaultRetriesCount(qgetenv("OWNCLOUD_BLACKLIST_COUNT").toInt());
|
||||
if (defaultRetriesCount.fetchAndAddAcquire(0) <= 0) {
|
||||
@@ -61,10 +63,17 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
||||
|
||||
switch( status ) {
|
||||
case SyncFileItem::SoftError:
|
||||
// do not blacklist in case of soft error.
|
||||
break;
|
||||
case SyncFileItem::FatalError:
|
||||
// do not blacklist in case of soft error or fatal error.
|
||||
break;
|
||||
case SyncFileItem::NormalError:
|
||||
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
|
||||
if (_item._httpErrorCode / 100 == 5) {
|
||||
// In this configuration, never blacklist error 5xx
|
||||
qDebug() << "Do not blacklist error " << _item._httpErrorCode;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
_propagator->_journal->updateBlacklistEntry( record );
|
||||
break;
|
||||
case SyncFileItem::Success:
|
||||
@@ -151,6 +160,8 @@ void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item )
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
|
||||
PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
|
||||
switch(item._instruction) {
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
@@ -208,10 +219,23 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
|
||||
QVector<PropagatorJob*> directoriesToRemove;
|
||||
QString removedDirectory;
|
||||
foreach(const SyncFileItem &item, items) {
|
||||
if (item._instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
&& !removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) {
|
||||
//already taken care of. (by the removal of the parent directory)
|
||||
continue;
|
||||
|
||||
if (!removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) {
|
||||
// this is an item in a directory which is going to be removed.
|
||||
if (item._instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
//already taken care of. (by the removal of the parent directory)
|
||||
continue;
|
||||
} else if (item._instruction == CSYNC_INSTRUCTION_NEW && item._isDirectory) {
|
||||
// create a new directory within a deleted directory? That can happen if the directory
|
||||
// etag were not fetched properly on the previous sync because the sync was aborted
|
||||
// while uploading this directory (which is now removed). We can ignore it.
|
||||
continue;
|
||||
} else if (item._instruction == CSYNC_INSTRUCTION_IGNORE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qWarning() << "WARNING: Job within a removed directory? This should not happen!"
|
||||
<< item._file << item._instruction;
|
||||
}
|
||||
|
||||
while (!item.destination().startsWith(directories.top().first)) {
|
||||
@@ -222,11 +246,21 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
|
||||
PropagateDirectory *dir = new PropagateDirectory(this, item);
|
||||
dir->_firstJob.reset(createJob(item));
|
||||
if (item._instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
//We do the removal of directories at the end
|
||||
//We do the removal of directories at the end, because there might be moves from
|
||||
// this directories that will happen later.
|
||||
directoriesToRemove.append(dir);
|
||||
removedDirectory = item._file + "/";
|
||||
|
||||
// We should not update the etag of parent directories of the removed directory
|
||||
// since it would be done before the actual remove (issue #1845)
|
||||
// NOTE: Currently this means that we don't update those etag at all in this sync,
|
||||
// but it should not be a problem, they will be updated in the next sync.
|
||||
for (int i = 0; i < directories.size(); ++i) {
|
||||
directories[i].second->_item._should_update_etag = false;
|
||||
}
|
||||
} else {
|
||||
directories.top().second->append(dir);
|
||||
PropagateDirectory* currentDirJob = directories.top().second;
|
||||
currentDirJob->append(dir);
|
||||
}
|
||||
directories.push(qMakePair(item.destination() + "/" , dir));
|
||||
} else if (PropagateItemJob* current = createJob(item)) {
|
||||
@@ -240,7 +274,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
|
||||
|
||||
connect(_rootJob.data(), SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
|
||||
connect(_rootJob.data(), SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64)));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SIGNAL(finished()));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished()));
|
||||
|
||||
qDebug() << (useLegacyJobs() ? "Using legacy libneon/HTTP sequential code path" : "Using QNAM/HTTP parallel code path");
|
||||
|
||||
@@ -279,6 +313,58 @@ bool OwncloudPropagator::useLegacyJobs()
|
||||
return env=="true" || env =="1";
|
||||
}
|
||||
|
||||
int OwncloudPropagator::httpTimeout()
|
||||
{
|
||||
static int timeout;
|
||||
if (!timeout) {
|
||||
timeout = qgetenv("OWNCLOUD_TIMEOUT").toUInt();
|
||||
if (timeout == 0) {
|
||||
MirallConfigFile cfg;
|
||||
timeout = cfg.timeout();
|
||||
}
|
||||
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
bool OwncloudPropagator::localFileNameClash( const QString& relFile )
|
||||
{
|
||||
bool re = false;
|
||||
const QString file( _localDir + relFile );
|
||||
|
||||
if( !file.isEmpty() && Utility::fsCasePreserving() ) {
|
||||
#ifdef Q_OS_MAC
|
||||
QFileInfo fileInfo(file);
|
||||
if (!fileInfo.exists()) {
|
||||
re = false;
|
||||
} else {
|
||||
re = ( ! fileInfo.canonicalFilePath().endsWith(relFile, Qt::CaseSensitive) );
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
const QString file( _localDir + relFile );
|
||||
qDebug() << "CaseClashCheck for " << file;
|
||||
WIN32_FIND_DATA FindFileData;
|
||||
HANDLE hFind;
|
||||
|
||||
hFind = FindFirstFileW( (wchar_t*)file.utf16(), &FindFileData);
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//qDebug() << "FindFirstFile failed " << GetLastError();
|
||||
// returns false.
|
||||
} else {
|
||||
QString realFileName = QString::fromWCharArray( FindFileData.cFileName );
|
||||
qDebug() << Q_FUNC_INFO << "Real file name is " << realFileName;
|
||||
FindClose(hFind);
|
||||
|
||||
if( ! file.endsWith(realFileName, Qt::CaseSensitive) ) {
|
||||
re = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return re;
|
||||
}
|
||||
|
||||
// ================================================================================
|
||||
|
||||
void PropagateDirectory::start()
|
||||
{
|
||||
@@ -337,5 +423,4 @@ void PropagateDirectory::slotSubJobReady()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ public:
|
||||
const QString _remoteFolder; // folder. (same as remoteDir but without remote.php/webdav)
|
||||
|
||||
SyncJournalDb * const _journal;
|
||||
bool _finishedEmited; // used to ensure that finished is only emit once
|
||||
|
||||
public:
|
||||
OwncloudPropagator(ne_session_s *session, const QString &localDir, const QString &remoteDir, const QString &remoteFolder,
|
||||
@@ -197,6 +198,7 @@ public:
|
||||
, _remoteDir((remoteDir.endsWith(QChar('/'))) ? remoteDir : remoteDir+'/' )
|
||||
, _remoteFolder((remoteFolder.endsWith(QChar('/'))) ? remoteFolder : remoteFolder+'/' )
|
||||
, _journal(progressDb)
|
||||
, _finishedEmited(false)
|
||||
, _activeJobs(0)
|
||||
{ }
|
||||
|
||||
@@ -210,17 +212,28 @@ public:
|
||||
/* The number of currently active jobs */
|
||||
int _activeJobs;
|
||||
|
||||
|
||||
bool isInSharedDirectory(const QString& file);
|
||||
|
||||
bool localFileNameClash(const QString& relfile);
|
||||
|
||||
void abort() {
|
||||
_abortRequested.fetchAndStoreOrdered(true);
|
||||
if (_rootJob)
|
||||
if (_rootJob) {
|
||||
_rootJob->abort();
|
||||
emit finished();
|
||||
}
|
||||
emitFinished();
|
||||
}
|
||||
|
||||
// timeout in seconds
|
||||
static int httpTimeout();
|
||||
|
||||
private slots:
|
||||
|
||||
/** Emit the finished signal and make sure it is only emit once */
|
||||
void emitFinished() {
|
||||
if (!_finishedEmited)
|
||||
emit finished();
|
||||
_finishedEmited = true;
|
||||
}
|
||||
|
||||
signals:
|
||||
void completed(const SyncFileItem &);
|
||||
|
||||
@@ -187,7 +187,8 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
|
||||
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
|
||||
{
|
||||
qDebug() << "Connect to url: " << url;
|
||||
_ocWizard->account()->setCredentials(_ocWizard->getCredentials());
|
||||
AbstractCredentials *creds = _ocWizard->getCredentials();
|
||||
_ocWizard->account()->setCredentials(creds);
|
||||
_ocWizard->setField(QLatin1String("OCUrl"), url );
|
||||
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
|
||||
.arg( Theme::instance()->appNameGUI() ).arg(url) );
|
||||
@@ -197,7 +198,9 @@ void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
|
||||
|
||||
void OwncloudSetupWizard::testOwnCloudConnect()
|
||||
{
|
||||
ValidateDavAuthJob *job = new ValidateDavAuthJob(_ocWizard->account(), this);
|
||||
Account *account = _ocWizard->account();
|
||||
|
||||
ValidateDavAuthJob *job = new ValidateDavAuthJob(account, this);
|
||||
job->setIgnoreCredentialFailure(true);
|
||||
connect(job, SIGNAL(authResult(QNetworkReply*)), SLOT(slotConnectionCheck(QNetworkReply*)));
|
||||
job->start();
|
||||
@@ -483,7 +486,8 @@ ValidateDavAuthJob::ValidateDavAuthJob(Account *account, QObject *parent)
|
||||
|
||||
void ValidateDavAuthJob::start()
|
||||
{
|
||||
QNetworkReply *reply = getRequest(account()->davPath());
|
||||
QString p = account()->davPath();
|
||||
QNetworkReply *reply = getRequest(p);
|
||||
setReply(reply);
|
||||
setupConnections(reply);
|
||||
AbstractNetworkJob::start();
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
ownCloudTheme::ownCloudTheme()
|
||||
ownCloudTheme::ownCloudTheme() :
|
||||
Theme()
|
||||
{
|
||||
// qDebug() << " ** running ownCloud theme!";
|
||||
}
|
||||
|
||||
@@ -108,7 +108,9 @@ ProgressDispatcher::~ProgressDispatcher()
|
||||
|
||||
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
|
||||
{
|
||||
if( folder.isEmpty() ) {
|
||||
if( folder.isEmpty() ||
|
||||
(progress._currentItems.size() == 0
|
||||
&& progress._totalFileCount == 0) ) {
|
||||
return;
|
||||
}
|
||||
emit progressInfo( folder, progress );
|
||||
|
||||
@@ -54,10 +54,12 @@ namespace Progress
|
||||
|
||||
void setProgressComplete(const SyncFileItem &item) {
|
||||
_currentItems.remove(item._file);
|
||||
if (Progress::isSizeDependent(item._instruction)) {
|
||||
_completedSize += item._size;
|
||||
if (!item._isDirectory) {
|
||||
_completedFileCount++;
|
||||
if (Progress::isSizeDependent(item._instruction)) {
|
||||
_completedSize += item._size;
|
||||
}
|
||||
}
|
||||
_completedFileCount++;
|
||||
_lastCompletedItem = item;
|
||||
}
|
||||
void setProgressItem(const SyncFileItem &item, quint64 size) {
|
||||
@@ -69,7 +71,8 @@ namespace Progress
|
||||
quint64 completedSize() const {
|
||||
quint64 r = _completedSize;
|
||||
foreach(const ProgressItem &i, _currentItems) {
|
||||
r += i._completedSize;
|
||||
if (!i._item._isDirectory)
|
||||
r += i._completedSize;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -305,6 +305,11 @@ bool PropagateNeonJob::updateMTimeAndETag(const char* uri, time_t mtime)
|
||||
|
||||
void PropagateNeonJob::limitBandwidth(qint64 progress, qint64 bandwidth_limit)
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||
// Do not limit bandwidth when aborting to speed up the current transfer
|
||||
return;
|
||||
}
|
||||
|
||||
if (bandwidth_limit > 0) {
|
||||
int64_t diff = _lastTime.nsecsElapsed() / 1000;
|
||||
int64_t len = progress - _lastProgress;
|
||||
@@ -444,6 +449,13 @@ void PropagateDownloadFileLegacy::start()
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||
return;
|
||||
|
||||
// do a case clash check.
|
||||
if( _propagator->localFileNameClash(_item._file) ) {
|
||||
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
||||
.arg(QDir::toNativeSeparators(_item._file)) );
|
||||
return;
|
||||
}
|
||||
|
||||
emit progress(_item, 0);
|
||||
|
||||
QString tmpFileName;
|
||||
|
||||
@@ -23,7 +23,8 @@ class PropagateUploadFileLegacy: public PropagateNeonJob {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropagateUploadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item)
|
||||
: PropagateNeonJob(propagator, item), _previousFileSize(0) {}
|
||||
: PropagateNeonJob(propagator, item)
|
||||
, _chunked_done(0), _chunked_total_size(0), _previousFileSize(0) {}
|
||||
void start();
|
||||
private:
|
||||
// Log callback for httpbf
|
||||
|
||||
@@ -22,10 +22,22 @@
|
||||
#include "propagatorjobs.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <cmath>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
static uint chunkSize() {
|
||||
static uint chunkSize;
|
||||
if (!chunkSize) {
|
||||
chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt();
|
||||
if (chunkSize == 0) {
|
||||
chunkSize = 10*1024*1024; // default to 10 MiB
|
||||
}
|
||||
}
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fiven an error from the network, map to a SyncFileItem::Status error
|
||||
*/
|
||||
@@ -61,19 +73,14 @@ void PUTFileJob::start() {
|
||||
}
|
||||
|
||||
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64)));
|
||||
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(resetTimeout()));
|
||||
|
||||
AbstractNetworkJob::start();
|
||||
}
|
||||
|
||||
static uint chunkSize() {
|
||||
static uint chunkSize;
|
||||
if (!chunkSize) {
|
||||
chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt();
|
||||
if (chunkSize == 0) {
|
||||
chunkSize = 10*1024*1024; // default to 10 MiB
|
||||
}
|
||||
}
|
||||
return chunkSize;
|
||||
void PUTFileJob::slotTimeout() {
|
||||
_errorString = tr("Connection Timeout");
|
||||
reply()->abort();
|
||||
}
|
||||
|
||||
void PropagateUploadFileQNAM::start()
|
||||
@@ -111,7 +118,6 @@ void PropagateUploadFileQNAM::start()
|
||||
}
|
||||
|
||||
struct ChunkDevice : QIODevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QIODevice *_file;
|
||||
qint64 _read;
|
||||
@@ -162,7 +168,6 @@ public:
|
||||
return _file->seek(pos + _start);
|
||||
}
|
||||
};
|
||||
#include "propagator_qnam.moc"
|
||||
|
||||
void PropagateUploadFileQNAM::startNextChunk()
|
||||
{
|
||||
@@ -195,7 +200,7 @@ void PropagateUploadFileQNAM::startNextChunk()
|
||||
}
|
||||
|
||||
QString path = _item._file;
|
||||
QIODevice *device;
|
||||
QIODevice *device = 0;
|
||||
if (_chunkCount > 1) {
|
||||
int sendingChunk = (_currentChunk + _startChunk) % _chunkCount;
|
||||
// XOR with chunk size to make sure everything goes well if chunk size change between runs
|
||||
@@ -213,13 +218,24 @@ void PropagateUploadFileQNAM::startNextChunk()
|
||||
} else {
|
||||
device = _file;
|
||||
}
|
||||
if (!device->isOpen())
|
||||
device->open(QIODevice::ReadOnly);
|
||||
|
||||
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
|
||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
|
||||
_job->start();
|
||||
bool isOpen = true;
|
||||
if (!device->isOpen()) {
|
||||
isOpen = device->open(QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
if( isOpen ) {
|
||||
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
|
||||
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
|
||||
_job->start();
|
||||
} else {
|
||||
qDebug() << "ERR: Could not open upload file: " << device->errorString();
|
||||
done( SyncFileItem::NormalError, device->errorString() );
|
||||
delete device;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateUploadFileQNAM::slotPutFinished()
|
||||
@@ -242,7 +258,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
"It is restored and your edit is in the conflict file."))) {
|
||||
return;
|
||||
}
|
||||
QString errorString = job->reply()->errorString();
|
||||
QString errorString = job->errorString();
|
||||
|
||||
QByteArray replyContent = job->reply()->readAll();
|
||||
qDebug() << replyContent; // display the XML error in the debug
|
||||
@@ -251,6 +267,12 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
|
||||
}
|
||||
|
||||
if (_item._httpErrorCode == 412) {
|
||||
// Precondition Failed: Maybe the bad etag is in the database, we need to clear the
|
||||
// parent folder etag so we won't read from DB next sync.
|
||||
_propagator->_journal->avoidReadFromDbOnNextSync(_item._file);
|
||||
}
|
||||
|
||||
done(classifyError(err, _item._httpErrorCode), errorString);
|
||||
return;
|
||||
}
|
||||
@@ -258,9 +280,14 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
bool finished = job->reply()->hasRawHeader("ETag");
|
||||
|
||||
if (!finished) {
|
||||
QFileInfo fi(_propagator->_localDir + _item._file);
|
||||
if( !fi.exists() ) {
|
||||
_propagator->_activeJobs--;
|
||||
done(SyncFileItem::SoftError, tr("The local file was removed during sync."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Utility::qDateTimeToTime_t(QFileInfo(_propagator->_localDir + _item._file).lastModified())
|
||||
!= _item._modtime) {
|
||||
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
|
||||
/* Uh oh: The local file has changed during upload */
|
||||
_propagator->_activeJobs--;
|
||||
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
||||
@@ -273,7 +300,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
_currentChunk++;
|
||||
if (_currentChunk >= _chunkCount) {
|
||||
_propagator->_activeJobs--;
|
||||
done(SyncFileItem::NormalError, tr("The server did not aknoledge the last chunk. (No e-tag were present)"));
|
||||
done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag were present)"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -288,6 +315,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
// the following code only happens after all chunks were uploaded.
|
||||
//
|
||||
// the file id should only be empty for new files up- or downloaded
|
||||
QByteArray fid = job->reply()->rawHeader("OC-FileID");
|
||||
if( !fid.isEmpty() ) {
|
||||
@@ -372,8 +401,8 @@ void GETFileJob::start() {
|
||||
|
||||
void GETFileJob::slotMetaDataChanged()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << reply()->error() << reply()->errorString() << reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
if (reply()->error() != QNetworkReply::NoError ) {
|
||||
if (reply()->error() != QNetworkReply::NoError
|
||||
|| reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) {
|
||||
// We will handle the error when the job is finished.
|
||||
return;
|
||||
}
|
||||
@@ -420,10 +449,9 @@ void GETFileJob::slotReadyRead()
|
||||
return;
|
||||
}
|
||||
}
|
||||
resetTimeout();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PropagateDownloadFileQNAM::start()
|
||||
{
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||
@@ -431,6 +459,13 @@ void PropagateDownloadFileQNAM::start()
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
|
||||
|
||||
// do a case clash check.
|
||||
if( _propagator->localFileNameClash(_item._file) ) {
|
||||
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
||||
.arg(QDir::toNativeSeparators(_item._file)) );
|
||||
return;
|
||||
}
|
||||
|
||||
emit progress(_item, 0);
|
||||
|
||||
QString tmpFileName;
|
||||
@@ -495,6 +530,7 @@ void PropagateDownloadFileQNAM::start()
|
||||
_job = new GETFileJob(AccountManager::instance()->account(),
|
||||
_propagator->_remoteFolder + _item._file,
|
||||
&_tmpFile, headers, expectedEtagForResume);
|
||||
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
||||
_propagator->_activeJobs ++;
|
||||
@@ -509,7 +545,9 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
||||
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS" << job->reply()->error() << job->reply()->errorString();
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< job->reply()->error()
|
||||
<< (job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : job->reply()->errorString());
|
||||
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
if (err != QNetworkReply::NoError) {
|
||||
@@ -611,5 +649,13 @@ void PropagateDownloadFileQNAM::abort()
|
||||
_job->reply()->abort();
|
||||
}
|
||||
|
||||
void GETFileJob::slotTimeout()
|
||||
{
|
||||
_errorString = tr("Connection Timeout");
|
||||
_errorStatus = SyncFileItem::FatalError;
|
||||
reply()->abort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class PUTFileJob : public AbstractNetworkJob {
|
||||
Q_OBJECT
|
||||
QIODevice* _device;
|
||||
QMap<QByteArray, QByteArray> _headers;
|
||||
QString _errorString;
|
||||
|
||||
public:
|
||||
// Takes ownership of the device
|
||||
@@ -67,6 +68,13 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
QString errorString() {
|
||||
return _errorString.isEmpty() ? reply()->errorString() : _errorString;
|
||||
};
|
||||
|
||||
virtual void slotTimeout();
|
||||
|
||||
|
||||
signals:
|
||||
void finishedSignal();
|
||||
void uploadProgress(qint64,qint64);
|
||||
@@ -124,6 +132,9 @@ public:
|
||||
|
||||
SyncFileItem::Status errorStatus() { return _errorStatus; }
|
||||
|
||||
virtual void slotTimeout();
|
||||
|
||||
|
||||
signals:
|
||||
void finishedSignal();
|
||||
void downloadProgress(qint64,qint64);
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
#include <neon/ne_compress.h>
|
||||
#include <neon/ne_redirect.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
@@ -81,9 +76,16 @@ void PropagateLocalRemove::start()
|
||||
return;
|
||||
|
||||
QString filename = _propagator->_localDir + _item._file;
|
||||
if( _propagator->localFileNameClash(_item._file)) {
|
||||
done(SyncFileItem::NormalError, tr("Could not remove %1 because of a local file name clash")
|
||||
.arg(QDir::toNativeSeparators(filename)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_item._isDirectory) {
|
||||
if (QDir(filename).exists() && !removeRecursively(filename)) {
|
||||
done(SyncFileItem::NormalError, tr("Could not remove directory %1").arg(filename));
|
||||
done(SyncFileItem::NormalError, tr("Could not remove directory %1")
|
||||
.arg(QDir::toNativeSeparators(filename)));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -104,9 +106,17 @@ void PropagateLocalMkdir::start()
|
||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||
return;
|
||||
|
||||
QDir d;
|
||||
if (!d.mkpath(_propagator->_localDir + _item._file)) {
|
||||
done(SyncFileItem::NormalError, tr("could not create directory %1").arg(_propagator->_localDir + _item._file));
|
||||
QDir newDir(_propagator->_localDir + _item._file);
|
||||
QString newDirStr = QDir::toNativeSeparators(newDir.path());
|
||||
if( Utility::fsCasePreserving() && newDir.exists() &&
|
||||
_propagator->localFileNameClash(_item._file ) ) {
|
||||
qDebug() << "WARN: new directory to create locally already exists!";
|
||||
done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
|
||||
return;
|
||||
}
|
||||
QDir localDir(_propagator->_localDir);
|
||||
if (!localDir.mkpath(_item._file)) {
|
||||
done( SyncFileItem::NormalError, tr("could not create directory %1").arg(newDirStr) );
|
||||
return;
|
||||
}
|
||||
done(SyncFileItem::Success);
|
||||
@@ -178,7 +188,19 @@ void PropagateLocalRename::start()
|
||||
if (_item._file != _item._renameTarget) {
|
||||
emit progress(_item, 0);
|
||||
qDebug() << "MOVE " << _propagator->_localDir + _item._file << " => " << _propagator->_localDir + _item._renameTarget;
|
||||
QFile::rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget);
|
||||
QFile file(_propagator->_localDir + _item._file);
|
||||
|
||||
if (_propagator->localFileNameClash(_item._renameTarget)) {
|
||||
// Fixme: the file that is the reason for the clash could be named here,
|
||||
// it would have to come out the localFileNameClash function
|
||||
done(SyncFileItem::NormalError, tr( "File %1 can not be renamed to %2 because of a local file name clash")
|
||||
.arg(QDir::toNativeSeparators(_item._file)).arg(QDir::toNativeSeparators(_item._renameTarget)) );
|
||||
return;
|
||||
}
|
||||
if (!file.rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget)) {
|
||||
done(SyncFileItem::NormalError, file.errorString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_propagator->_journal->deleteFileRecord(_item._originalFile);
|
||||
|
||||
@@ -81,6 +81,7 @@ class PropagateLocalMkdir : public PropagateItemJob {
|
||||
public:
|
||||
PropagateLocalMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {}
|
||||
void start();
|
||||
|
||||
};
|
||||
class PropagateRemoteRemove : public PropagateNeonJob {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -23,7 +23,17 @@ namespace Mirall {
|
||||
SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
|
||||
: MacPreferencesWindow(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
// do not show minimize button. There is no use, and retoring the
|
||||
// dialog from minimize is broken in MacPreferencesWindow
|
||||
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint |
|
||||
Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
|
||||
|
||||
|
||||
// Emulate dialog behavior: Escape means close
|
||||
QAction *closeWindowAction = new QAction(this);
|
||||
closeWindowAction->setShortcut(QKeySequence(Qt::Key_Escape));
|
||||
connect(closeWindowAction, SIGNAL(triggered()), SLOT(close()));
|
||||
addAction(closeWindowAction);
|
||||
|
||||
setObjectName("SettingsMac"); // required as group for saveGeometry call
|
||||
|
||||
@@ -51,8 +61,6 @@ SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
|
||||
|
||||
connect( ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, Progress::Info)),
|
||||
_accountSettings, SLOT(slotSetProgress(QString, Progress::Info)) );
|
||||
connect( ProgressDispatcher::instance(), SIGNAL(progressSyncProblem(QString,Progress::SyncProblem)),
|
||||
_accountSettings, SLOT(slotProgressProblem(QString,Progress::SyncProblem)) );
|
||||
|
||||
QAction *showLogWindow = new QAction(this);
|
||||
showLogWindow->setShortcut(QKeySequence("F12"));
|
||||
|
||||
@@ -83,7 +83,7 @@ QMenu* SslButton::buildCertMenu(QMenu *parent, const QSslCertificate& cert,
|
||||
QLatin1String("<br/>") +
|
||||
Utility::escape(Utility::formatFingerprint(sha265hash.mid(sha265hash.length()/2), false));
|
||||
#endif
|
||||
QString serial = QString::fromUtf8(cert.serialNumber(), true);
|
||||
QString serial = QString::fromUtf8(cert.serialNumber());
|
||||
QString effectiveDate = cert.effectiveDate().date().toString();
|
||||
QString expiryDate = cert.expiryDate().date().toString();
|
||||
QString sna = QStringList(cert.alternateSubjectNames().values()).join(" ");
|
||||
|
||||
@@ -52,20 +52,25 @@ void csyncLogCatcher(int /*verbosity*/,
|
||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||
}
|
||||
|
||||
/* static variables to hold the credentials */
|
||||
QMutex SyncEngine::_syncMutex;
|
||||
bool SyncEngine::_syncRunning = false;
|
||||
|
||||
SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remoteURL, const QString& remotePath, Mirall::SyncJournalDb* journal)
|
||||
: _csync_ctx(ctx)
|
||||
, _needsUpdate(false)
|
||||
, _localPath(localPath)
|
||||
, _remoteUrl(remoteURL)
|
||||
, _remotePath(remotePath)
|
||||
, _journal(journal)
|
||||
, _hasFiles(false)
|
||||
, _downloadLimit(0)
|
||||
, _uploadLimit(0)
|
||||
|
||||
{
|
||||
_localPath = localPath;
|
||||
_remotePath = remotePath;
|
||||
_remoteUrl = remoteURL;
|
||||
_csync_ctx = ctx;
|
||||
_journal = journal;
|
||||
qRegisterMetaType<SyncFileItem>("SyncFileItem");
|
||||
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
|
||||
qRegisterMetaType<Progress::Info>("Progress::Info");
|
||||
|
||||
_thread.setObjectName("CSync_Neon_Thread");
|
||||
_thread.start();
|
||||
}
|
||||
|
||||
@@ -265,7 +270,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
item._fileId = file->file_id;
|
||||
|
||||
// record the seen files to be able to clean the journal later
|
||||
_seenFiles[item._file] = QString();
|
||||
_seenFiles.insert(item._file);
|
||||
|
||||
switch(file->error_status) {
|
||||
case CSYNC_STATUS_OK:
|
||||
@@ -292,6 +297,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
item._modtime = file->modtime;
|
||||
item._etag = file->etag;
|
||||
item._size = file->size;
|
||||
item._inode = file->inode;
|
||||
|
||||
item._should_update_etag = file->should_update_etag;
|
||||
switch( file->type ) {
|
||||
case CSYNC_FTW_TYPE_DIR:
|
||||
@@ -412,18 +419,13 @@ void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) {
|
||||
} else {
|
||||
emit csyncError(errStr);
|
||||
}
|
||||
csync_commit(_csync_ctx);
|
||||
emit finished();
|
||||
_syncMutex.unlock();
|
||||
_thread.quit();
|
||||
finalize();
|
||||
}
|
||||
|
||||
void SyncEngine::startSync()
|
||||
{
|
||||
if (!_syncMutex.tryLock()) {
|
||||
qDebug() << Q_FUNC_INFO << "WARNING: Another sync seems to be running. Not starting a new one.";
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(!_syncRunning);
|
||||
_syncRunning = true;
|
||||
|
||||
if( ! _csync_ctx ) {
|
||||
qDebug() << "XXXXXXXXXXXXXXXX FAIL: do not have csync_ctx!";
|
||||
@@ -449,12 +451,7 @@ void SyncEngine::startSync()
|
||||
if( fileRecordCount == -1 ) {
|
||||
qDebug() << "No way to create a sync journal!";
|
||||
emit csyncError(tr("Unable to initialize a sync journal."));
|
||||
|
||||
csync_commit(_csync_ctx);
|
||||
emit finished();
|
||||
_syncMutex.unlock();
|
||||
_thread.quit();
|
||||
|
||||
finalize();
|
||||
return;
|
||||
// database creation error!
|
||||
} else if ( fileRecordCount < 50 ) {
|
||||
@@ -499,6 +496,9 @@ void SyncEngine::startSync()
|
||||
// csync_set_auth_callback( _csync_ctx, getauth );
|
||||
csync_set_log_callback( csyncLogCatcher );
|
||||
//csync_set_log_level( 11 ); don't set the loglevel here, it shall be done by folder.cpp or owncloudcmd.cpp
|
||||
int timeout = OwncloudPropagator::httpTimeout();
|
||||
csync_set_module_property(_csync_ctx, "timeout", &timeout);
|
||||
|
||||
|
||||
_stopWatch.start();
|
||||
|
||||
@@ -548,9 +548,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
|
||||
if (!_journal->isConnected()) {
|
||||
qDebug() << "Bailing out, DB failure";
|
||||
emit csyncError(tr("Cannot open the sync journal"));
|
||||
emit finished();
|
||||
_syncMutex.unlock();
|
||||
_thread.quit();
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -564,9 +562,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
|
||||
emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel);
|
||||
if (cancel) {
|
||||
qDebug() << Q_FUNC_INFO << "Abort sync";
|
||||
emit finished();
|
||||
_syncMutex.unlock();
|
||||
_thread.quit();
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -586,7 +582,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
|
||||
connect(_propagator.data(), SIGNAL(progress(SyncFileItem,quint64)),
|
||||
this, SLOT(slotProgress(SyncFileItem,quint64)));
|
||||
connect(_propagator.data(), SIGNAL(adjustTotalTransmissionSize(qint64)), this, SLOT(slotAdjustTotalTransmissionSize(qint64)));
|
||||
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()));
|
||||
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()), Qt::QueuedConnection);
|
||||
|
||||
setNetworkLimits();
|
||||
|
||||
@@ -664,18 +660,24 @@ void SyncEngine::slotFinished()
|
||||
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
|
||||
qDebug() << "Cleaning of synced ";
|
||||
}
|
||||
|
||||
_journal->commit("All Finished.", false);
|
||||
emit treeWalkResult(_syncedItems);
|
||||
finalize();
|
||||
}
|
||||
|
||||
void SyncEngine::finalize()
|
||||
{
|
||||
_thread.quit();
|
||||
_thread.wait();
|
||||
csync_commit(_csync_ctx);
|
||||
|
||||
qDebug() << "CSync run took " << _stopWatch.addLapTime(QLatin1String("Sync Finished"));
|
||||
_stopWatch.stop();
|
||||
|
||||
emit finished();
|
||||
_propagator.reset(0);
|
||||
_syncMutex.unlock();
|
||||
_thread.quit();
|
||||
_syncRunning = false;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void SyncEngine::slotProgress(const SyncFileItem& item, quint64 current)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
#include <qelapsedtimer.h>
|
||||
|
||||
#include <csync.h>
|
||||
@@ -101,7 +102,10 @@ private:
|
||||
int treewalkFile( TREE_WALK_FILE*, bool );
|
||||
bool checkBlacklisting( SyncFileItem *item );
|
||||
|
||||
static QMutex _syncMutex;
|
||||
// cleanup and emit the finished signal
|
||||
void finalize();
|
||||
|
||||
static bool _syncRunning; //true when one sync is running somewhere (for debugging)
|
||||
SyncFileItemVector _syncedItems;
|
||||
|
||||
CSYNC *_csync_ctx;
|
||||
@@ -112,7 +116,7 @@ private:
|
||||
SyncJournalDb *_journal;
|
||||
QScopedPointer <OwncloudPropagator> _propagator;
|
||||
QString _lastDeleted; // if the last item was a path and it has been deleted
|
||||
QHash <QString, QString> _seenFiles;
|
||||
QSet<QString> _seenFiles;
|
||||
QThread _thread;
|
||||
|
||||
Progress::Info _progressInfo;
|
||||
|
||||
@@ -49,8 +49,9 @@ public:
|
||||
FileIgnored ///< The file is in the ignored list
|
||||
};
|
||||
|
||||
SyncFileItem() : _type(UnknownType), _direction(None), _instruction(CSYNC_INSTRUCTION_NONE),
|
||||
_should_update_etag(false), _blacklistedInDb(false),
|
||||
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
|
||||
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0),
|
||||
_size(0), _inode(0), _should_update_etag(false), _blacklistedInDb(false),
|
||||
_status(NoStatus), _httpErrorCode(0), _requestDuration(0) {}
|
||||
|
||||
friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) {
|
||||
@@ -83,6 +84,7 @@ public:
|
||||
time_t _modtime;
|
||||
QByteArray _etag;
|
||||
quint64 _size;
|
||||
quint64 _inode;
|
||||
bool _should_update_etag;
|
||||
QByteArray _fileId;
|
||||
bool _blacklistedInDb;
|
||||
|
||||
@@ -491,7 +491,7 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
|
||||
return rec;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::postSyncCleanup(const QHash<QString, QString> &items )
|
||||
bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
@@ -770,7 +770,15 @@ void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item
|
||||
return;
|
||||
}
|
||||
|
||||
query.prepare("SELECT retrycount FROM blacklist WHERE path=:path");
|
||||
QString sql("SELECT retrycount FROM blacklist WHERE path=:path");
|
||||
|
||||
if( Utility::fsCasePreserving() ) {
|
||||
// if the file system is case preserving we have to check the blacklist
|
||||
// case insensitively
|
||||
sql += QLatin1String(" COLLATE NOCASE");
|
||||
}
|
||||
|
||||
query.prepare(sql);
|
||||
query.bindValue(":path", item._file);
|
||||
|
||||
if( !query.exec() ) {
|
||||
@@ -827,6 +835,28 @@ void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
|
||||
}
|
||||
}
|
||||
|
||||
void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
|
||||
{
|
||||
//Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
|
||||
//get the info from the server
|
||||
// We achieve that by clearing the etag of the parents directory recursively
|
||||
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if( !checkConnect() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
QSqlQuery query(_db);
|
||||
// This query will match entries for whitch the path is a prefix of fileName
|
||||
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ? LIKE(path||'/%') AND type == 2"); // CSYNC_FTW_TYPE_DIR == 2
|
||||
query.bindValue(0, fileName);
|
||||
if( !query.exec() ) {
|
||||
qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
|
||||
} else {
|
||||
qDebug() << query.executedQuery() << fileName;
|
||||
}
|
||||
}
|
||||
|
||||
void SyncJournalDb::commit(const QString& context, bool startTrans)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
bool _valid;
|
||||
};
|
||||
struct UploadInfo {
|
||||
UploadInfo() : _chunk(0), _transferid(0), _errorCount(0), _valid(false) {}
|
||||
UploadInfo() : _chunk(0), _transferid(0), _size(0), _errorCount(0), _valid(false) {}
|
||||
int _chunk;
|
||||
int _transferid;
|
||||
quint64 _size; //currently unused
|
||||
@@ -73,7 +73,13 @@ public:
|
||||
SyncJournalBlacklistRecord blacklistEntry( const QString& );
|
||||
void avoidRenamesOnNextSync(const QString &path);
|
||||
|
||||
bool postSyncCleanup( const QHash<QString, QString>& items );
|
||||
/**
|
||||
* Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
|
||||
* get the info from the server
|
||||
*/
|
||||
void avoidReadFromDbOnNextSync(const QString& fileName);
|
||||
|
||||
bool postSyncCleanup( const QSet<QString>& items );
|
||||
|
||||
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions
|
||||
* Commit will actually commit the transaction and create a new one.
|
||||
|
||||
@@ -36,15 +36,20 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
|
||||
_type(item._type), _etag(item._etag), _fileId(item._fileId),
|
||||
_uid(0), _gid(0), _mode(0)
|
||||
{
|
||||
// use the "old" inode coming with the item for the case where the
|
||||
// filesystem stat fails. That can happen if the the file was removed
|
||||
// or renamed meanwhile. For the rename case we still need the inode to
|
||||
// detect the rename tough.
|
||||
_inode = item._inode;
|
||||
|
||||
// Query the inode:
|
||||
// based on code from csync_vio_local.c (csync_vio_local_stat)
|
||||
#ifdef Q_OS_WIN
|
||||
/* Get the Windows file id as an inode replacement. */
|
||||
/* Query the inode:
|
||||
based on code from csync_vio_local.c (csync_vio_local_stat)
|
||||
Get the Windows file id as an inode replacement. */
|
||||
HANDLE h = CreateFileW( (wchar_t*)localFileName.utf16(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
|
||||
if( h == INVALID_HANDLE_VALUE ) {
|
||||
_inode = 0;
|
||||
qWarning() << "Failed to query the 'inode' because CreateFileW failed for file " << localFileName;
|
||||
} else {
|
||||
BY_HANDLE_FILE_INFORMATION fileInfo;
|
||||
@@ -60,7 +65,7 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
|
||||
_inode = FileIndex.QuadPart;
|
||||
} else {
|
||||
qWarning() << "Failed to query the 'inode' for file " << localFileName;
|
||||
_inode = 0;
|
||||
|
||||
}
|
||||
CloseHandle(h);
|
||||
}
|
||||
@@ -68,7 +73,6 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
|
||||
struct stat sb;
|
||||
if( stat(QFile::encodeName(localFileName).constData(), &sb) < 0) {
|
||||
qWarning() << "Failed to query the 'inode' for file " << localFileName;
|
||||
_inode = 0;
|
||||
} else {
|
||||
_inode = sb.st_ino;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ Theme* Theme::_instance = 0;
|
||||
Theme* Theme::instance() {
|
||||
if (!_instance) {
|
||||
_instance = new THEME_CLASS;
|
||||
// some themes may not call the base ctor
|
||||
_instance->_mono = false;
|
||||
}
|
||||
return _instance;
|
||||
@@ -151,6 +152,13 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
Theme::Theme() :
|
||||
QObject(0)
|
||||
,_mono(false)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// if this option return true, the client only supports one folder to sync.
|
||||
@@ -212,7 +220,7 @@ QString Theme::about() const
|
||||
"<p>Distributed by %4 and licensed under the GNU General Public License (GPL) Version 2.0.<br>"
|
||||
"%5 and the %5 logo are registered trademarks of %4 in the<br>"
|
||||
"United States, other countries, or both.</p>")
|
||||
.arg(MIRALL_VERSION_MAJOR).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
||||
.arg(MIRALL_VERSION_STRING).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
||||
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN)).arg(APPLICATION_VENDOR).arg(APPLICATION_NAME);
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
|
||||
protected:
|
||||
QIcon themeIcon(const QString& name, bool sysTray = false) const;
|
||||
Theme() {}
|
||||
Theme();
|
||||
|
||||
signals:
|
||||
void systrayUseMonoIconsChanged(bool);
|
||||
|
||||
@@ -143,7 +143,7 @@ QString Utility::platform()
|
||||
return QLatin1String("Linux");
|
||||
#elif defined(__DragonFly__) // Q_OS_FREEBSD also defined
|
||||
return QLatin1String("DragonFlyBSD");
|
||||
#elif defined(Q_OS_FREEBSD)
|
||||
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL)
|
||||
return QLatin1String("FreeBSD");
|
||||
#elif defined(Q_OS_NETBSD)
|
||||
return QLatin1String("NetBSD");
|
||||
@@ -167,20 +167,9 @@ QByteArray Utility::userAgentString()
|
||||
void Utility::raiseDialog( QWidget *raiseWidget )
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
// viel hilft viel ;-)
|
||||
if( raiseWidget ) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) && \
|
||||
(defined(Q_OS_WIN) || defined (Q_OS_MAC))
|
||||
Qt::WindowFlags eFlags = raiseWidget->windowFlags();
|
||||
if (!(eFlags & Qt::WindowStaysOnTopHint)) {
|
||||
eFlags |= Qt::WindowStaysOnTopHint;
|
||||
raiseWidget->setWindowFlags(eFlags);
|
||||
raiseWidget->show();
|
||||
eFlags &= ~Qt::WindowStaysOnTopHint;
|
||||
raiseWidget->setWindowFlags(eFlags);
|
||||
}
|
||||
#endif
|
||||
raiseWidget->show();
|
||||
if( raiseWidget && raiseWidget->parentWidget() == 0) {
|
||||
// Qt has a bug which causes parent-less dialogs to pop-under.
|
||||
raiseWidget->showNormal();
|
||||
raiseWidget->raise();
|
||||
raiseWidget->activateWindow();
|
||||
}
|
||||
@@ -199,7 +188,7 @@ void Utility::setLaunchOnStartup(const QString &appName, const QString& guiName,
|
||||
|
||||
qint64 Utility::freeDiskSpace(const QString &path, bool *ok)
|
||||
{
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL)
|
||||
struct statvfs stat;
|
||||
statvfs(path.toUtf8().data(), &stat);
|
||||
return (qint64) stat.f_bavail * stat.f_frsize;
|
||||
@@ -348,6 +337,15 @@ static bool checkDolphinCanSelect()
|
||||
return p.readAll().contains("--select");
|
||||
}
|
||||
|
||||
bool Utility::fsCasePreserving()
|
||||
{
|
||||
bool re = false;
|
||||
if( isWindows() || isMac() ) {
|
||||
re = true;
|
||||
}
|
||||
return re;
|
||||
}
|
||||
|
||||
// inspired by Qt Creator's showInGraphicalShell();
|
||||
void Utility::showInFileManager(const QString &localPath)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user