Comparar commits

..

22 Commits

Autor SHA1 Mensagem Data
Jenkins for ownCloud b66125baa7 [tx-robot] updated from transifex 2013-07-30 01:26:48 -04:00
Jenkins for ownCloud 1bc7468287 [tx-robot] updated from transifex 2013-07-28 01:27:25 -04:00
Jenkins for ownCloud bb5ea68807 [tx-robot] updated from transifex 2013-07-24 01:26:42 -04:00
Jenkins for ownCloud 9641ed1202 [tx-robot] updated from transifex 2013-07-22 01:26:25 -04:00
Jenkins for ownCloud c736439440 [tx-robot] updated from transifex 2013-07-21 01:26:20 -04:00
Jenkins for ownCloud 50674cf153 [tx-robot] updated from transifex 2013-07-18 01:26:22 -04:00
Jenkins for ownCloud 7270644e84 [tx-robot] updated from transifex 2013-07-17 02:15:53 -04:00
Jenkins for ownCloud 43b4ddd722 [tx-robot] updated from transifex 2013-07-16 01:27:18 -04:00
Jenkins for ownCloud bdd91712e7 [tx-robot] updated from transifex 2013-07-15 17:11:07 -04:00
Jenkins for ownCloud 72efce1416 [tx-robot] updated from transifex 2013-07-14 01:45:10 +02:00
Jenkins for ownCloud 3ff8db10e8 [tx-robot] updated from transifex 2013-07-13 01:26:34 +02:00
Klaas Freitag 24bdf60bd7 Documented the docexpire option.
(cherry picked from commit 5da6103fb5)
2013-07-12 18:17:18 +02:00
Daniel Molkentin 79924d5eec Detect missing system tray
Fixes #497
(cherry picked from commit a63863b65c)
2013-07-12 18:16:48 +02:00
Daniel Molkentin 4cebcce735 Folder wizard: Warn if a chosen dir is read-only
Fixes #755
2013-07-12 13:36:25 +02:00
Jenkins for ownCloud 48441ccb96 [tx-robot] updated from transifex 2013-07-11 01:28:57 +02:00
Jenkins for ownCloud 183fe2735d [tx-robot] updated from transifex 2013-07-09 01:29:53 +02:00
Jenkins for ownCloud 957dea03a6 [tx-robot] updated from transifex 2013-07-06 01:28:00 +02:00
Jenkins for ownCloud 859f79087f [tx-robot] updated from transifex 2013-07-05 01:26:53 +02:00
Jenkins for ownCloud 9be49c0c9a [tx-robot] updated from transifex 2013-07-04 09:37:46 +02:00
Jenkins for ownCloud 3fdc8aeecb [tx-robot] updated from transifex 2013-07-02 15:39:13 +02:00
Jenkins for ownCloud 68085915c4 [tx-robot] updated from transifex 2013-06-29 01:58:03 +02:00
Jenkins for ownCloud ca4ad7b71c [tx-robot] updated from transifex 2013-06-28 01:27:27 +02:00
207 arquivos alterados com 70193 adições e 50727 exclusões
+2 -4
Ver Arquivo
@@ -4,8 +4,6 @@ project(mirall)
set(PACKAGE "mirall")
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
include(Warnings)
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
include ( ${OEM_THEME_DIR}/OEM.cmake )
@@ -64,9 +62,9 @@ endif()
####
#### find libs
find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED )
find_package(Qt4 4.6.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest REQUIRED )
if( UNIX AND NOT APPLE ) # Fdo notifications
find_package(Qt4 4.7.0 COMPONENTS QtDBus REQUIRED )
find_package(Qt4 4.6.0 COMPONENTS QtDBus REQUIRED )
endif()
find_package(Csync REQUIRED)
if(UNIX)
-28
Ver Arquivo
@@ -1,33 +1,5 @@
ChangeLog
=========
version 1.4.0beta1 (release 2013-08-08 ), csync 0.81.0 required
* New Scheduler: Only sync when there are actual changes in the server
* Add a Settings Dialog, move Proxy Settings there
* Transform folder Status Dialog into Account Settings, provide feedback via context menu
* Add Bandwidth Control
* Add a visual storage/quota indicator (context menu and account settings)
* Add progress indication (context menu and account settings)
* Introduce a sync history, persisting results across syncs
* Move ability to switch to mono icons from a switch to a Settings option
* Add "Launch on System Startup" GUI option
* Add "Show Desktop Nofications"GUI option (enabled by default)
top optionally disable sync notifications
* Add Help item, pointing to online reference
* Implement graphical selection of remote folders in FolderWizard
* Allow custom ignore patterns
* Add an editor for ingore patterns
* ALlow to flag certain ignore patterns as discardable
* Ensure to ship with all valid translations
* Add preliminary support for Shibboleth authentication
* Linux: Provide more icon sizes
* Linux: Do not trigger notifier on ignored files
* Windows: Reduce priority of CSync thread
* Documentation: Prem. updates to reflect UI changes
* Significant code refactorings
* Require Qt 4.7
* Known issue: Under certain conditions, a file will only get uploaded after up to five minutes
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
* Default proxy port to 8080
+2 -2
Ver Arquivo
@@ -1,6 +1,6 @@
set( VERSION_MAJOR 1 )
set( VERSION_MINOR 4 )
set( VERSION_MINOR 3 )
set( VERSION_PATCH 0 )
set( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta2")
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX})
set( SOVERSION 0 )
+93 -12
Ver Arquivo
@@ -18,6 +18,7 @@
!define OPTION_SECTION_SC_START_MENU
!define OPTION_SECTION_SC_DESKTOP
!define OPTION_SECTION_SC_QUICK_LAUNCH
!define OPTION_SECTION_SC_AUTOSTART
!define OPTION_FINISHPAGE
!define OPTION_FINISHPAGE_LAUNCHER
; !define OPTION_FINISHPAGE_RELEASE_NOTES
@@ -282,20 +283,84 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
!ifndef INSTALL_PATH
;Main executable.
File "${BUILD_PATH}\bin\${APPLICATION_EXECUTABLE}"
File "${BUILD_PATH}\src\lib${APPLICATION_SHORTNAME}sync.dll"
File "${BUILD_PATH}\src\libowncloudsync.dll"
File "${BUILD_PATH}\src\mirall_*.qm"
; Make sure only to copy qt, not qt_help, etc
File "${MING_SHARE}\qt4\translations\qt_??.qm"
File "${MING_SHARE}\qt4\translations\qt_??_??.qm"
File "${MING_SHARE}\qt4\translations\qtkeychain_*.qm"
File "${BUILD_PATH}\src\mirall_ca.qm"
File "${BUILD_PATH}\src\mirall_cs_CZ.qm"
File "${BUILD_PATH}\src\mirall_da.qm"
File "${BUILD_PATH}\src\mirall_de.qm"
File "${BUILD_PATH}\src\mirall_el.qm"
File "${BUILD_PATH}\src\mirall_en.qm"
File "${BUILD_PATH}\src\mirall_eo.qm"
File "${BUILD_PATH}\src\mirall_es.qm"
File "${BUILD_PATH}\src\mirall_es_AR.qm"
File "${BUILD_PATH}\src\mirall_et_EE.qm"
File "${BUILD_PATH}\src\mirall_eu.qm"
File "${BUILD_PATH}\src\mirall_fa.qm"
File "${BUILD_PATH}\src\mirall_fi_FI.qm"
File "${BUILD_PATH}\src\mirall_fr.qm"
File "${BUILD_PATH}\src\mirall_gl.qm"
File "${BUILD_PATH}\src\mirall_he.qm"
File "${BUILD_PATH}\src\mirall_hr.qm"
File "${BUILD_PATH}\src\mirall_hu_HU.qm"
File "${BUILD_PATH}\src\mirall_it.qm"
File "${BUILD_PATH}\src\mirall_ja_JP.qm"
File "${BUILD_PATH}\src\mirall_ko.qm"
File "${BUILD_PATH}\src\mirall_lb.qm"
File "${BUILD_PATH}\src\mirall_lt_LT.qm"
File "${BUILD_PATH}\src\mirall_lv.qm"
File "${BUILD_PATH}\src\mirall_mk.qm"
File "${BUILD_PATH}\src\mirall_ms_MY.qm"
File "${BUILD_PATH}\src\mirall_nb_NO.qm"
File "${BUILD_PATH}\src\mirall_nl.qm"
File "${BUILD_PATH}\src\mirall_oc.qm"
File "${BUILD_PATH}\src\mirall_pl.qm"
File "${BUILD_PATH}\src\mirall_pt_BR.qm"
File "${BUILD_PATH}\src\mirall_pt_PT.qm"
File "${BUILD_PATH}\src\mirall_ro.qm"
File "${BUILD_PATH}\src\mirall_ru.qm"
File "${BUILD_PATH}\src\mirall_ru_RU.qm"
File "${BUILD_PATH}\src\mirall_si_LK.qm"
File "${BUILD_PATH}\src\mirall_sk_SK.qm"
File "${BUILD_PATH}\src\mirall_sl.qm"
File "${BUILD_PATH}\src\mirall_sr@latin.qm"
File "${BUILD_PATH}\src\mirall_sv.qm"
File "${BUILD_PATH}\src\mirall_ta_LK.qm"
File "${BUILD_PATH}\src\mirall_th_TH.qm"
File "${BUILD_PATH}\src\mirall_tr.qm"
File "${BUILD_PATH}\src\mirall_uk.qm"
File "${BUILD_PATH}\src\mirall_vi.qm"
File "${BUILD_PATH}\src\mirall_zh_CN.qm"
File "${BUILD_PATH}\src\mirall_zh_TW.qm"
#File "${MING_SHARE}\qt4\translations\qt_ar.qm"
File "${MING_SHARE}\qt4\translations\qt_cs.qm"
File "${MING_SHARE}\qt4\translations\qt_da.qm"
File "${MING_SHARE}\qt4\translations\qt_de.qm"
File "${MING_SHARE}\qt4\translations\qt_es.qm"
File "${MING_SHARE}\qt4\translations\qt_fa.qm"
File "${MING_SHARE}\qt4\translations\qt_fr.qm"
File "${MING_SHARE}\qt4\translations\qt_gl.qm"
File "${MING_SHARE}\qt4\translations\qt_he.qm"
File "${MING_SHARE}\qt4\translations\qt_hu.qm"
File "${MING_SHARE}\qt4\translations\qt_ja.qm"
File "${MING_SHARE}\qt4\translations\qt_ko.qm"
File "${MING_SHARE}\qt4\translations\qt_lt.qm"
File "${MING_SHARE}\qt4\translations\qt_pl.qm"
File "${MING_SHARE}\qt4\translations\qt_pt.qm"
File "${MING_SHARE}\qt4\translations\qt_ru.qm"
File "${MING_SHARE}\qt4\translations\qt_sk.qm"
File "${MING_SHARE}\qt4\translations\qt_sl.qm"
File "${MING_SHARE}\qt4\translations\qt_sv.qm"
File "${MING_SHARE}\qt4\translations\qt_uk.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_CN.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
File "${MING_SHARE}\qt4\translations\qtkeychain_de.qm"
SetOutPath "$INSTDIR\accessible"
File "${ACCESSIBLE_DLL_PATH}\qtaccessiblewidgets4.dll"
SetOutPath "$INSTDIR\imageformats"
File "${IMAGEFORMATS_DLL_PATH}\qgif4.dll"
File "${IMAGEFORMATS_DLL_PATH}\qjpeg4.dll"
File "${IMAGEFORMATS_DLL_PATH}\qico4.dll"
SetOutPath "$INSTDIR\modules"
; FIXME: fix installation dir of module, currently needs manual copying to
@@ -316,7 +381,6 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
File "${QT_DLL_PATH}\QtGui4.dll"
File "${QT_DLL_PATH}\QtNetwork4.dll"
File "${QT_DLL_PATH}\QtXml4.dll"
File "${QT_DLL_PATH}\QtWebKit4.dll"
;QtKeyChain stuff
File "${MING_BIN}\libqtkeychain.dll"
@@ -340,7 +404,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
; Other
;File "${MING_BIN}\libpng15-15.dll"
File "${MING_BIN}\libjpeg-8.dll"
;File "${MING_BIN}\libjpeg-8.dll"
File "${MING_BIN}\zlib1.dll"
File "${MING_BIN}\libcrypto-10.dll"
File "${MING_BIN}\libssl-10.dll"
@@ -391,6 +455,17 @@ SectionGroup "Shortcuts"
SectionGroupEnd
!ifdef OPTION_SECTION_SC_AUTOSTART
${MementoSection} "Autostart" SEC_AUTOSTART
SectionIn 1 2
SetDetailsPrint textonly
DetailPrint "Creating Windows Start Entry"
SetDetailsPrint listonly
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Run" \
"${APPLICATION_NAME}" "$INSTDIR\${APPLICATION_EXECUTABLE}"
${MementoSectionEnd}
!endif
${MementoSectionDone}
; Installer section descriptions
@@ -400,6 +475,7 @@ ${MementoSectionDone}
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} program group."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_AUTOSTART} "Register ${APPLICATION_NAME} to run on Windows startup."
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section -post
@@ -502,6 +578,11 @@ Section Uninstall
DeleteRegKey HKCR "${APPLICATION_NAME}"
;Windows Start entry
!ifdef OPTION_SECTION_SC_AUTOSTART
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPLICATION_NAME}"
!endif
;Start menu shortcuts.
!ifdef OPTION_SECTION_SC_START_MENU
SetShellVarContext all
-20
Ver Arquivo
@@ -1,20 +0,0 @@
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Wno-long-long")
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
endif(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
endif(CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
if(DEFINED MIRALL_FATAL_WARNINGS)
if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
endif(DEFINED MIRALL_FATAL_WARNINGS)
+1
Ver Arquivo
@@ -2,6 +2,7 @@
#define CONFIG_H
#cmakedefine USE_INOTIFY 1
#cmakedefine WITH_CSYNC 1
#cmakedefine WITH_QTKEYCHAIN 1
#cmakedefine GIT_SHA1 "@GIT_SHA1@"
+5 -5
Ver Arquivo
@@ -27,7 +27,7 @@ if(SPHINX_FOUND)
# apt-get install texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
add_custom_target(doc-latex ${SPHINX_EXECUTABLE}
-q -c . -b latex
-d ${SPHINX_CACHE_DIR}/latex
-d ${SPHINX_CACHE_DIR}
-D latex_logo=${LATEX_LOGO}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_PDF_DIR} )
@@ -41,7 +41,7 @@ if(SPHINX_FOUND)
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
-q -c . -b qthelp
-d ${SPHINX_CACHE_DIR}/qthelp
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_QCH_DIR} )
add_custom_target( doc-qch ${QT_QCOLLECTIONGENERATOR_EXECUTABLE}
@@ -54,12 +54,12 @@ if(SPHINX_FOUND)
endif()
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
-q -c . -b html
-d ${SPHINX_CACHE_DIR}/html
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTML_DIR} )
add_custom_target( doc-man ${SPHINX_EXECUTABLE}
-q -c . -b man
-d ${SPHINX_CACHE_DIR}/man
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_MAN_DIR} )
@@ -71,7 +71,7 @@ if(SPHINX_FOUND)
add_custom_target( doc-chm-sphinx ${SPHINX_EXECUTABLE}
-q -c . -b htmlhelp
-D html_theme=basic
-d ${SPHINX_CACHE_DIR}/htmlhelp
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTMLHELP_DIR} )
add_custom_target( doc-chm pushd ${SPHINX_HTMLHELP_DIR}; ${MSHTML_COMPILER} *.hhp; popd
+153
Ver Arquivo
@@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OwncloudDocumentation.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OwncloudDocumentation.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OwncloudDocumentation"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OwncloudDocumentation"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
+19 -53
Ver Arquivo
@@ -34,13 +34,8 @@ server is always master.
This is the major difference to other systems like a file backup where just
changes and new files are propagated but files never get deleted.
The oCC checks both repositories for changes frequently after a certain time
span. That is refered to as a sync run. In between the local repository is
monitored by a file system monitor system that starts a sync run immediately
if something was edited, added or removed.
Sync by Time versus ETag
------------------------
Sync Direction and Strategies
-----------------------------
.. index:: time stamps, file times, etag, unique id
Until the release of ownCloud 4.5 and ownCloud Client 1.1, ownCloud employed
@@ -49,7 +44,7 @@ synced to the other repository: the files modification time.
The *modification timestamp* is part of the files metadata. It is available on
every relevant filesystem and is the natural indicator for a file change.
Modification timestamps do not require special action to create and have
modification timestamps do not require special action to create and have
a general meaning. One design goal of csync is to not require a special server
component, thats why it was chosen as the backend component.
@@ -62,22 +57,29 @@ machines.
Since this strategy is rather fragile without NTP, ownCloud 4.5 introduced a
unique number, which changes whenever the file changes. Although it is a unique
value, it is not a hash of the file, but a randomly chosen number, which it will
transmit in the Etag_ field. Since the file number is guaranteed to change if the
file changes, it can now be used to determine if one of the files has changed.
transmit in the Etag_ field. The client will store this number in a
per-directory database, located in the application directory (version 1.1) or
as a hidden file right in the directory to be synced (later versions).
Since the file number is guaranteed to change if the file changes, it can now be
used to determine if one of the files has changed.
.. note:: oCC 1.1 and newer require file ID capabilities on the ownCloud server,
hence using them with a server earlier than 4.5.0 is not supported.
Before the 1.3.0 release of the client the sync process might create faux conflict
files if time deviates. The original and the conflict files only differed in the
timestamp, but not in content. This behaviour was changed towards a binary check
if the files are different.
.. todo:: describe what happens if both sides change
If the per-directory database gets removed, oCC's CSync backend will fall back
to a time-stamp based sync process to rebuild the database. Thus it should be
made sure that both server and client synchronized to NTP time before
restarting the client after a database removal. If time deviates, the sync
process might create faux conflict files, which only differ in their time.
Those need to be cleaned up manually later on and will not be synced back
to the server. However, no files will get deleted in this process.
Just like files, directories also hold a unique id, which changes whenever
one of the contained files or directories gets modified. Since this is a
recursive process, it significantly reduces the effort required for a sync
cycle, because the client will only walk directories with a modified unique id.
.. note:: oCC 1.1 and newer require file ID capabilities on the ownCloud server,
hence using them with a server earlier than 4.5.0 is not supported.
This table outlines the different sync methods attempted depending
on server/client combination:
@@ -104,39 +106,3 @@ are involved and one of them is not in sync with NTP time.
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
Comparison and Conflict Cases
----------------------------
In a sync run the client first has to detect if one of the two repositories have
changed files. On the local repository, the client traverses the file
tree and compares the modification time of each file with the value it was
before. The previous value is stored in the client's database. If it is not, it
means that the file has been added to the local repository. Note that on
the local side, the modificaton time a good attribute to detect changes because
it does not depend on time shifts and such.
For the remote (ie. ownCloud) repository, the client compares the ETag of each
file with it's previous value. Again the previous value is queried from the
database. If the ETag is still the same, the file has not changed.
So what happens if a file has changed on both, the local and the remote repository
since the last sync run? That means it can not easily be decided which version
of the file is the one that should be used. Moreover, changes to any side must
not be lost. That is called the conflict case and the client solves it by creating
a conflict file of the older of the two files and save the newer one under the
original file name. Conflict files are always created on the client and never on
the server. The conflict file has the same name as the original file appended
with the timestamp of the conflict detection.
The Sync Journal
----------------
The client stores the ETag number in a per-directory database, called the journal.
It is located in the application directory (until version 1.1) or as a hidden file
right in the directory to be synced (later versions).
If the journal database gets removed, oCC's CSync backend will rebuild the database
by comparing the files and their modification times. Thus it should be made sure
that both server and client synchronized to NTP time before restarting the client
after a database removal.
The oCC also provides a button in the Settings Dialog that allows to "reset" the
journal. That can be used to recreate the journal database.
+1 -1
Ver Arquivo
@@ -37,7 +37,7 @@ Next, install the missing dependencies::
brew install $(brew deps ocsync)
brew install $(brew deps mirall)
To build mirall and csync, follow the `generic build instructions`_.
To build mirall and cmake, follow the `generic build instructions`_.
.. note::
You should not call ``make install`` at any time, since the product of the
+6 -12
Ver Arquivo
@@ -1,23 +1,17 @@
ownCloud Client supports the following command line switches:
``--logwindow``
open a window to show log output.
open a window to show log output at startup.
``--logfile`` `<filename>`
write log output to file <filename>.
``--logfile`` `<file>`
write log output to a single file
``--logdir`` `<name>`
write each sync log output in a new file in directory <name>
``--logdir`` `<dir>`
write log output to dir, one for each sync run.
``--logexpire`` `<hours>`
removes logs older than <hours> hours. (to be used with --logdir)
``--logflush``
``--flushlog``
flush the log file after every write.
``--monoicons``
Use black/white pictograms for systray.
``--confdir`` `<dirname>`
Use the given configuration directory.
+11 -51
Ver Arquivo
@@ -26,63 +26,23 @@ also opens the status dialog.
The dialog provides an overview on the configured sync folders and allows to add
and remove more sync folder connections as well as pausing a sync connection.
Changing Your Password and Account Settings
-------------------------------------------
Changing your password
----------------------
In the ``Settings`` Dialog, choose ``Account`` -> ``Modify Account``. It will open
Setup Wizard, which next to reconfiguring your connection to use a different
user or server also will allow to change the password for the local account,
or to switch from HTTP to HTTPS.
Use the ``Configure`` option. It will open the Connection Wizard, which next to
reconfiguring your connection to use a different user or server also will allow
to change the password for the local account, or to switch from HTTP to HTTPS.
Setting up a Proxy
Setting up a proxy
------------------
By default, the configured system proxy will be picked up. This may not be
working reliably on some Linux distributions, as only the ``http_proxy``
variable gets picked up. You can configure a proxy different from your
system default in the ``Network`` section of the ``Settings`` dialog.
working reliable on some Linux distributions, as only the ``http_proxy``
variable gets parsed. You can configure a proxy different from your
system default by choosing ``Configure proxy...`` from the menu.
The default settings assume an HTTP proxy, which is the typical use case.
If you require SOCKS 5 proxy, pick ``SOCKS5 proxy`` instead of ``HTTP(S) proxy``
from the drop down menu. SOCKS 5 proxies are typically provided by some
SSH implementations, for instance OpenSSH's ``-D`` parameter. This is
useful for scenarios where SSH is employed to securely tunnel a client
to the network running the ownCloud server.
Limiting Bandwidth
------------------
Starting with Version 1.4, the Client provides bandwidth limiter.
This option can be found in the ``Network`` section of the
``Settings Dialog``.
You will find two settings for ``Download Bandwidth`` and
``Upload Bandwidth``.
Upload Bandwidth
~~~~~~~~~~~~~~~~
The default is to automatically limit the upload. The rationale
for this default is that typically, Computers and laptops are
not directly connected to the server, but via a Cable Modems
or DSL lines, which provide significantly more downstream than
upstream bandwith. Sataurating the upstream bandwidth would
interfere with other applications, especially Voice-Over-IP or
Games.
The automatic limiter will throttle the speed to about 75%
of the available upstream bandwidth. If you are communicating
with the server via a fast, symetric connection, you can set the
Limiter to ``No Limit`` instead. If want a stronger limitation,
choose ``Limit to`` and specify a limit manually.
Download Bandwidth
~~~~~~~~~~~~~~~~~~
Because the download bandwidth is usually no concern, it is not
automatically limited. Should you find that the Client is taking
up too much bandwidth, you can manually specify a limit (in KB).
By default, ownCloud expects a HTTP proxy. If you want to specify a SOCKS5
proxy instead, tick the "Use as SOCKSv5 proxy" option.
Options
-------
-1
Ver Arquivo
@@ -5,4 +5,3 @@ Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
GenericName=Folder Sync
Icon=@APPLICATION_SHORTNAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing
-2
Ver Arquivo
@@ -10,8 +10,6 @@
<file>resources/task-ongoing.png</file>
<file>resources/view-refresh.png</file>
<file>resources/warning-16.png</file>
<file>resources/settings.png</file>
<file>resources/network.png</file>
<file>resources/owncloud_logo_blue.png</file>
</qresource>
</RCC>
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.1 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 2.7 KiB

+29 -88
Ver Arquivo
@@ -11,22 +11,15 @@ else()
set(theme_dir ${CMAKE_CURRENT_SOURCE_DIR}/../theme)
endif()
set(synclib_NAME ${APPLICATION_SHORTNAME}sync)
set(mirall_UI
mirall/folderwizardsourcepage.ui
mirall/folderwizardtargetpage.ui
mirall/statusdialog.ui
mirall/owncloudsetuppage_ng.ui
mirall/owncloudwizardresultpage.ui
mirall/sslerrordialog.ui
mirall/settingsdialog.ui
mirall/generalsettings.ui
mirall/networksettings.ui
mirall/accountsettings.ui
mirall/ignorelisteditor.ui
mirall/itemprogressdialog.ui
wizard/owncloudsetupnocredspage.ui
wizard/owncloudhttpcredspage.ui
wizard/owncloudwizardresultpage.ui
wizard/owncloudadvancedsetuppage.ui
mirall/proxydialog.ui
mirall/fileitemdialog.ui
)
set(3rdparty_SRC
@@ -69,6 +62,8 @@ set(libsync_SRCS
mirall/syncresult.cpp
mirall/networklocation.cpp
mirall/mirallconfigfile.cpp
mirall/credentialstore.cpp
mirall/owncloudfolder.cpp
mirall/csyncthread.cpp
mirall/fileutils.cpp
mirall/theme.cpp
@@ -77,47 +72,17 @@ set(libsync_SRCS
mirall/logger.cpp
mirall/utility.cpp
mirall/connectionvalidator.cpp
mirall/progressdispatcher.cpp
mirall/mirallaccessmanager.cpp
creds/dummycredentials.cpp
creds/httpcredentials.cpp
creds/credentialsfactory.cpp
creds/http/credentialstore.cpp
creds/http/httpconfigfile.cpp
creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethaccessmanager.cpp
creds/shibboleth/shibbolethcookiejar.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethconfigfile.cpp
creds/credentialscommon.cpp
)
set(libsync_HEADERS
set(libsync_HEADERS
mirall/folderman.h
mirall/folder.h
mirall/folderwatcher.h
mirall/owncloudfolder.h
mirall/csyncthread.h
mirall/theme.h
mirall/owncloudtheme.h
mirall/owncloudinfo.h
mirall/credentialstore.h
mirall/logger.h
mirall/connectionvalidator.h
mirall/progressdispatcher.h
mirall/mirallaccessmanager.h
creds/abstractcredentials.h
creds/dummycredentials.h
creds/httpcredentials.h
creds/credentialsfactory.h
creds/http/credentialstore.h
creds/http/httpconfigfile.h
creds/shibbolethcredentials.h
creds/shibboleth/shibbolethaccessmanager.h
creds/shibboleth/shibbolethcookiejar.h
creds/shibboleth/shibbolethwebview.h
creds/shibboleth/shibbolethrefresher.h
creds/shibboleth/shibbolethconfigfile.h
creds/credentialscommon.h
)
IF( INOTIFY_FOUND )
@@ -148,20 +113,20 @@ if(QTKEYCHAIN_FOUND)
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
endif()
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
set_target_properties( ${synclib_NAME} PROPERTIES
add_library(owncloudsync SHARED ${libsync_SRCS} ${syncMoc})
set_target_properties( owncloudsync PROPERTIES
VERSION ${VERSION}
SOVERSION ${SOVERSION}
)
target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} )
target_link_libraries(owncloudsync ${libsync_LINK_TARGETS} )
if ( APPLE )
target_link_libraries(${synclib_NAME} /System/Library/Frameworks/CoreServices.framework)
target_link_libraries(owncloudsync /System/Library/Frameworks/CoreServices.framework)
endif()
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
install(TARGETS ${synclib_NAME}
install(TARGETS owncloudsync
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -172,32 +137,22 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_SHORTNAME}.desktop DESTINATION share/applications )
endif()
else()
install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
install(TARGETS owncloudsync DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
endif()
set(mirall_SRCS
mirall/application.cpp
mirall/systray.cpp
mirall/folderwizard.cpp
mirall/folderstatusmodel.cpp
wizard/owncloudwizard.cpp
wizard/owncloudsetuppage.cpp
wizard/owncloudhttpcredspage.cpp
wizard/owncloudwizardresultpage.cpp
wizard/owncloudwizardcommon.cpp
wizard/owncloudshibbolethcredspage.cpp
wizard/owncloudadvancedsetuppage.cpp
mirall/statusdialog.cpp
mirall/owncloudwizard.cpp
mirall/owncloudsetupwizard.cpp
mirall/updatedetector.cpp
mirall/occinfo.cpp
mirall/sslerrordialog.cpp
mirall/logbrowser.cpp
mirall/settingsdialog.cpp
mirall/generalsettings.cpp
mirall/networksettings.cpp
mirall/accountsettings.cpp
mirall/ignorelisteditor.cpp
mirall/itemprogressdialog.cpp
mirall/proxydialog.cpp
mirall/fileitemdialog.cpp
)
set(mirall_HEADERS
@@ -205,23 +160,13 @@ set(mirall_HEADERS
mirall/systray.h
mirall/folderwizard.h
mirall/owncloudsetupwizard.h
wizard/owncloudwizard.h
wizard/owncloudsetuppage.h
wizard/owncloudhttpcredspage.h
wizard/owncloudwizardresultpage.h
wizard/owncloudwizardcommon.h
wizard/owncloudshibbolethcredspage.h
wizard/owncloudadvancedsetuppage.h
mirall/folderstatusmodel.h
mirall/owncloudwizard.h
mirall/statusdialog.h
mirall/updatedetector.h
mirall/sslerrordialog.h
mirall/logbrowser.h
mirall/settingsdialog.h
mirall/generalsettings.h
mirall/networksettings.h
mirall/accountsettings.h
mirall/ignorelisteditor.h
mirall/itemprogressdialog.h
mirall/proxydialog.h
mirall/fileitemdialog.h
)
if( UNIX AND NOT APPLE)
@@ -262,16 +207,12 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
if(NOT WIN32)
file( GLOB _icons "${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-*.png" )
foreach( _file ${_icons} )
string( REPLACE "${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-" "" _res ${_file} )
string( REPLACE ".png" "" _res ${_res} )
install( FILES ${_file} RENAME ${APPLICATION_SHORTNAME}.png DESTINATION
${CMAKE_INSTALL_DATADIR}/icons/hicolor/${_res}x${_res}/apps )
endforeach( _file )
install(FILES
${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-48.png
DESTINATION share/icons/hicolor/48x48/apps/ RENAME ${APPLICATION_SHORTNAME}.png)
endif(NOT WIN32)
install(FILES ${mirall_I18N} DESTINATION share/${APPLICATION_SHORTNAME}/i18n)
install(FILES ${mirall_I18N} DESTINATION share/mirall/i18n)
# we may not add MACOSX_BUNDLE here, if not building one
@@ -309,7 +250,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
)
target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
target_link_libraries( ${APPLICATION_EXECUTABLE} owncloudsync )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${CSYNC_LIBRARY} )
install(TARGETS ${APPLICATION_EXECUTABLE}
-47
Ver Arquivo
@@ -1,47 +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_ABSTRACT_CREDENTIALS_H
#define MIRALL_CREDS_ABSTRACT_CREDENTIALS_H
#include <QObject>
#include <csync.h>
class QNetworkAccessManager;
namespace Mirall
{
class AbstractCredentials : public QObject
{
Q_OBJECT
public:
// No need for virtual destructor - QObject already has one.
virtual void syncContextPreInit(CSYNC* ctx) = 0;
virtual void syncContextPreStart(CSYNC* ctx) = 0;
virtual bool changed(AbstractCredentials* credentials) const = 0;
virtual QString authType() const = 0;
virtual QNetworkAccessManager* getQNAM() const = 0;
virtual bool ready() const = 0;
virtual void fetch() = 0;
virtual void persistForUrl(const QString& url) = 0;
Q_SIGNALS:
void fetched();
};
} // ns Mirall
#endif
-77
Ver Arquivo
@@ -1,77 +0,0 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QList>
#include <QRegExp>
#include <QString>
#include <QSslCertificate>
#include "creds/credentialscommon.h"
#include "mirall/utility.h"
#include "mirall/owncloudinfo.h"
namespace Mirall
{
int handleNeonSSLProblems(const char* prompt,
char* buf,
size_t /*len*/,
int /*echo*/,
int /*verify*/,
void* /*userdata*/)
{
int re = 0;
const QString qPrompt = QString::fromLatin1( prompt ).trimmed();
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
// SSL is requested. If the program came here, the SSL check was done by mirall
// It needs to be checked if the chain is still equal to the one which
// was verified by the user.
const QRegExp regexp("fingerprint: ([\\w\\d:]+)");
bool certOk = false;
int pos = 0;
// This is the set of certificates which QNAM accepted, so we should accept
// them as well
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
QString neon_fingerprint = regexp.cap(1);
foreach( const QSslCertificate& c, certs ) {
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
if( verified_shasum == neon_fingerprint ) {
certOk = true;
break;
}
}
}
// certOk = false; DEBUG setting, keep disabled!
if( !certOk ) { // Problem!
qstrcpy( buf, "no" );
re = -1;
} else {
qstrcpy( buf, "yes" ); // Certificate is fine!
}
} else {
qDebug() << "Unknown prompt: <" << prompt << ">";
re = -1;
}
return re;
}
} // ns Mirall
-32
Ver Arquivo
@@ -1,32 +0,0 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_COMMON_H
#define MIRALL_CREDS_COMMON_H
namespace Mirall
{
int handleNeonSSLProblems(const char* prompt,
char* buf,
size_t len,
int echo,
int verify,
void* userdata);
} // ns Mirall
#endif
-43
Ver Arquivo
@@ -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.
*/
#include <QString>
#include "creds/httpcredentials.h"
#include "creds/dummycredentials.h"
#include "creds/shibbolethcredentials.h"
namespace Mirall
{
namespace CredentialsFactory
{
AbstractCredentials* create(const QString& type)
{
// empty string might happen for old version of configuration
if (type == "http" || type == "") {
return new HttpCredentials;
} else if (type == "dummy") {
return new DummyCredentials;
} else if (type == "shibboleth") {
return new ShibbolethCredentials;
} else {
qWarning("Unknown credentials type: %s", qPrintable(type));
return new DummyCredentials;
}
}
} // ns CredentialsFactory
} // ns Mirall
-32
Ver Arquivo
@@ -1,32 +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_CREDENTIALS_FACTORY_H
#define MIRALL_CREDS_CREDENTIALS_FACTORY_H
class AbstractCredentials;
class QString;
namespace Mirall
{
namespace CredentialsFactory
{
AbstractCredentials* create(const QString& type);
} // ns CredentialsFactory
} // ns Mirall
#endif
-56
Ver Arquivo
@@ -1,56 +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/dummycredentials.h"
#include "mirall/mirallaccessmanager.h"
namespace Mirall
{
void DummyCredentials::syncContextPreInit(CSYNC*)
{}
void DummyCredentials::syncContextPreStart(CSYNC*)
{}
bool DummyCredentials::changed(AbstractCredentials* credentials) const
{
DummyCredentials* dummy(dynamic_cast< DummyCredentials* >(credentials));
return dummy == 0;
}
QString DummyCredentials::authType() const
{
return QString::fromLatin1("dummy");
}
QNetworkAccessManager* DummyCredentials::getQNAM() const
{
return new MirallAccessManager;
}
bool DummyCredentials::ready() const
{
return true;
}
void DummyCredentials::fetch()
{
Q_EMIT(fetched());
}
void DummyCredentials::persistForUrl(const QString&)
{}
} // ns Mirall
-39
Ver Arquivo
@@ -1,39 +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_DUMMY_CREDENTIALS_H
#define MIRALL_CREDS_DUMMY_CREDENTIALS_H
#include "creds/abstractcredentials.h"
namespace Mirall
{
class DummyCredentials : public AbstractCredentials
{
Q_OBJECT
public:
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
void fetch();
void persistForUrl(const QString& url);
};
} // ns Mirall
#endif
-81
Ver Arquivo
@@ -1,81 +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/http/httpconfigfile.h"
namespace Mirall
{
namespace
{
const char userC[] = "user";
const char passwdC[] = "passwd";
const char oldPasswdC[] = "password";
} // ns
QString HttpConfigFile::user() const
{
return retrieveData(QString(), QLatin1String(userC)).toString();
}
void HttpConfigFile::setUser(const QString& user)
{
storeData(QString(), QLatin1String(userC), QVariant(user));
}
QString HttpConfigFile::password() const
{
const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC)));
if (passwd.isValid()) {
return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray()));
}
return QString();
}
void HttpConfigFile::setPassword(const QString& password)
{
QByteArray pwdba = password.toUtf8();
storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) );
removeOldPassword();
}
bool HttpConfigFile::passwordExists() const
{
return dataExists(QString(), QLatin1String(passwdC));
}
void HttpConfigFile::removePassword()
{
removeOldPassword();
removeData(QString(), QLatin1String(passwdC));
}
void HttpConfigFile::fixupOldPassword()
{
const QString old(QString::fromLatin1(oldPasswdC));
if (dataExists(QString(), old)) {
setPassword(retrieveData(QString(), old).toString());
}
}
void HttpConfigFile::removeOldPassword()
{
removeData(QString(), QLatin1String(oldPasswdC));
}
} // ns Mirall
-40
Ver Arquivo
@@ -1,40 +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_HTTP_CONFIG_FILE_H
#define MIRALL_CREDS_HTTP_CONFIG_FILE_H
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
class HttpConfigFile : public MirallConfigFile
{
public:
QString user() const;
void setUser(const QString& user);
QString password() const;
void setPassword(const QString& password);
bool passwordExists() const;
void removePassword();
void fixupOldPassword();
private:
void removeOldPassword();
};
} // ns Mirall
#endif
-218
Ver Arquivo
@@ -1,218 +0,0 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QMutex>
#include "creds/httpcredentials.h"
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h"
#include "creds/http/credentialstore.h"
#include "creds/credentialscommon.h"
namespace Mirall
{
namespace
{
int getauth(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
int re = 0;
QMutex mutex;
MirallConfigFile cfg;
HttpCredentials* http_credentials = dynamic_cast< HttpCredentials* > (cfg.getCredentials());
if (!http_credentials) {
qDebug() << "Not a HTTP creds instance!";
return -1;
}
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
QString user = http_credentials->user();
QString pwd = http_credentials->password();
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
QMutexLocker locker( &mutex );
qstrncpy( buf, user.toUtf8().constData(), len );
} else if( qPrompt == QLatin1String("Enter your password:") ) {
QMutexLocker locker( &mutex );
// qDebug() << "OOO Password requested!";
qstrncpy( buf, pwd.toUtf8().constData(), len );
} else {
re = handleNeonSSLProblems(prompt, buf, len, echo, verify, userdata);
}
return re;
}
} // ns
HttpCredentials::HttpCredentials()
: _user(),
_password(),
_ready(false),
_attempts()
{}
HttpCredentials::HttpCredentials(const QString& user, const QString& password)
: _user(user),
_password(password),
_ready(true)
{}
void HttpCredentials::syncContextPreInit (CSYNC* ctx)
{
csync_set_auth_callback (ctx, getauth);
}
void HttpCredentials::syncContextPreStart (CSYNC* ctx)
{
// TODO: This should not be a part of this method, but we don't have
// any way to get "session_key" module property from csync. Had we
// have it, then we could remove this code and keep it in
// csyncthread code (or folder code, git remembers).
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
QString cookiesAsString;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
cookiesAsString += c.name();
cookiesAsString += '=';
cookiesAsString += c.value();
cookiesAsString += "; ";
}
csync_set_module_property(ctx, "session_key", cookiesAsString.toLatin1().data());
}
bool HttpCredentials::changed(AbstractCredentials* credentials) const
{
HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials));
if (!other || other->user() != this->user()) {
return true;
}
return false;
}
QString HttpCredentials::authType() const
{
return QString::fromLatin1("http");
}
QString HttpCredentials::user() const
{
return _user;
}
QString HttpCredentials::password() const
{
return _password;
}
QNetworkAccessManager* HttpCredentials::getQNAM() const
{
MirallAccessManager* qnam = new MirallAccessManager;
connect( qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*)));
return qnam;
}
bool HttpCredentials::ready() const
{
return _ready;
}
void HttpCredentials::fetch()
{
if (_ready) {
Q_EMIT fetched();
} else {
// TODO: merge CredentialStore into HttpCredentials?
CredentialStore* store(CredentialStore::instance());
connect(store, SIGNAL(fetchCredentialsFinished(bool)),
this, SLOT(slotCredentialsFetched(bool)));
store->fetchCredentials();
}
}
void HttpCredentials::persistForUrl(const QString& url)
{
CredentialStore* store(CredentialStore::instance());
store->setCredentials(url, _user, _password);
store->saveCredentials();
}
void HttpCredentials::slotCredentialsFetched(bool ok)
{
_ready = ok;
if (_ready) {
CredentialStore* store(CredentialStore::instance());
_user = store->user();
_password = store->password();
}
Q_EMIT fetched();
}
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)
{
if( !(authenticator && reply) ) return;
qDebug() << "Authenticating request for " << reply->url();
if (_attempts.contains(reply)) {
++_attempts[reply];
} else {
connect(reply, SIGNAL(finished()),
this, SLOT(slotReplyFinished()));
_attempts[reply] = 1;
}
// TODO: Replace it with something meaningful...
//if( reply->url().toString().startsWith( webdavUrl( _connection ) ) ) {
if (_attempts[reply] > 1) {
qDebug() << "Too many attempts to authenticate. Stop request.";
reply->close();
} else {
authenticator->setUser( _user );
authenticator->setPassword( _password );
}
//} else {
// qDebug() << "WRN: attempt to authenticate to different url - closing.";
// reply->close();
//}
}
void HttpCredentials::slotReplyFinished()
{
QNetworkReply* reply = qobject_cast< QNetworkReply* >(sender());
disconnect(reply, SIGNAL(finished()),
this, SLOT(slotReplyFinished()));
_attempts.remove (reply);
}
} // ns Mirall
-64
Ver Arquivo
@@ -1,64 +0,0 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_HTTP_CREDENTIALS_H
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
#include <QMap>
#include "creds/abstractcredentials.h"
class QNetworkReply;
class QAuthenticator;
namespace Mirall
{
class HttpCredentials : public AbstractCredentials
{
Q_OBJECT
public:
HttpCredentials();
HttpCredentials(const QString& user, const QString& password);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
void fetch();
void persistForUrl(const QString& url);
QString user() const;
QString password() const;
private Q_SLOTS:
void slotCredentialsFetched(bool);
void slotAuthentication(QNetworkReply*, QAuthenticator*);
void slotReplyFinished();
private:
QString _user;
QString _password;
bool _ready;
QMap<QNetworkReply*, int> _attempts;
};
} // ns Mirall
#endif
@@ -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 "creds/shibboleth/shibbolethaccessmanager.h"
namespace Mirall
{
ShibbolethAccessManager::ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent)
: MirallAccessManager (parent),
_cookie(cookie)
{}
QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
if (!_cookie.name().isEmpty()) {
QNetworkCookieJar* jar(cookieJar());
QUrl url(request.url());
QList<QNetworkCookie> cookies;
Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) {
if (!cookie.name().startsWith("_shibsession_")) {
cookies << cookie;
}
}
cookies << _cookie;
jar->setCookiesFromUrl(cookies, url);
}
qDebug() << "Creating a request to " << request.url().toString() << " with shibboleth cookie:" << _cookie.name();
return MirallAccessManager::createRequest (op, request, outgoingData);
}
void ShibbolethAccessManager::setCookie(const QNetworkCookie& cookie)
{
qDebug() << "Got new shibboleth cookie:" << cookie.name();
_cookie = cookie;
}
} // ns Mirall
@@ -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
-104
Ver Arquivo
@@ -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
-38
Ver Arquivo
@@ -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
-34
Ver Arquivo
@@ -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
-41
Ver Arquivo
@@ -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
-52
Ver Arquivo
@@ -1,52 +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 <QEventLoop>
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
namespace Mirall
{
ShibbolethRefresher::ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
: QObject(parent),
_creds(creds),
_csync_ctx(csync_ctx)
{}
void ShibbolethRefresher::refresh()
{
QEventLoop loop;
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
QMetaObject::invokeMethod(_creds, "invalidateAndFetch", Qt::QueuedConnection);
loop.exec();
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
}
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
{
// "cookies" is const and its data() return const void*. We want just void*.
QByteArray myCookies(cookies);
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
}
} // ns Mirall
-47
Ver Arquivo
@@ -1,47 +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_REFRESHER_H
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
#include <QObject>
#include <csync.h>
class QByteArray;
namespace Mirall
{
class ShibbolethCredentials;
class ShibbolethRefresher : public QObject
{
Q_OBJECT
public:
ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
void refresh();
private Q_SLOTS:
void onInvalidatedAndFetched(const QByteArray& cookieData);
private:
ShibbolethCredentials* _creds;
CSYNC* _csync_ctx;
};
} // ns Mirall
#endif
-104
Ver Arquivo
@@ -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 <QApplication>
#include <QDebug>
#include <QNetworkCookie>
#include <QWebFrame>
#include <QWebPage>
#include "creds/shibboleth/shibbolethcookiejar.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "mirall/mirallaccessmanager.h"
namespace Mirall
{
void ShibbolethWebView::setup(const QUrl& url, ShibbolethCookieJar* jar)
{
MirallAccessManager* nm = new MirallAccessManager(this);
QWebPage* page = new QWebPage(this);
jar->setParent(this);
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
connect(page, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
connect(page, SIGNAL(loadFinished(bool)),
this, SLOT(slotLoadFinished()));
nm->setCookieJar(jar);
page->setNetworkAccessManager(nm);
page->mainFrame ()->load (url);
this->setPage (page);
}
ShibbolethWebView::ShibbolethWebView(const QUrl& url, QWidget* parent)
: QWebView(parent)
{
setup(url, new ShibbolethCookieJar(this));
}
ShibbolethWebView::~ShibbolethWebView()
{
slotLoadFinished();
}
ShibbolethWebView::ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent)
: QWebView(parent)
{
setup(url, jar);
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
QList<QNetworkCookie> otherCookies;
QNetworkCookie shibCookie;
Q_FOREACH (const QNetworkCookie& cookie, cookieList) {
if (cookie.name().startsWith ("_shibsession_")) {
if (shibCookie.name().isEmpty()) {
shibCookie = cookie;
} else {
qWarning() << "Too many Shibboleth session cookies at once!";
}
} else {
otherCookies << cookie;
}
}
if (!otherCookies.isEmpty()) {
Q_EMIT otherCookiesReceived(otherCookies, url);
}
if (!shibCookie.name().isEmpty()) {
Q_EMIT shibbolethCookieReceived(shibCookie);
}
}
void ShibbolethWebView::hideEvent(QHideEvent* event)
{
Q_EMIT viewHidden();
QWebView::hideEvent(event);
}
void ShibbolethWebView::slotLoadStarted()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
void ShibbolethWebView::slotLoadFinished()
{
QApplication::restoreOverrideCursor();
}
} // ns Mirall
-56
Ver Arquivo
@@ -1,56 +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_WEB_VIEW_H
#define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
#include <QList>
#include <QWebView>
class QNetworkCookie;
class QUrl;
namespace Mirall
{
class ShibbolethCookieJar;
class ShibbolethWebView : public QWebView
{
Q_OBJECT
public:
ShibbolethWebView(const QUrl& url, QWidget* parent = 0);
ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent = 0);
~ShibbolethWebView();
protected:
void hideEvent(QHideEvent* event);
Q_SIGNALS:
void shibbolethCookieReceived(const QNetworkCookie& cookie);
void viewHidden();
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private Q_SLOTS:
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
void slotLoadStarted();
void slotLoadFinished();
private:
void setup(const QUrl& url, ShibbolethCookieJar* jar);
};
} // ns Mirall
#endif
-231
Ver Arquivo
@@ -1,231 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/credentialscommon.h"
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
namespace
{
int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri)
{
if (!csync_ctx || !uri) {
return 1;
}
const QString qurl(QString::fromLatin1(uri));
QRegExp shibbolethyWords ("SAML|wayf");
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
if (!qurl.contains(shibbolethyWords)) {
return 1;
}
QMutex mutex;
QMutexLocker locker(&mutex);
MirallConfigFile cfg;
ShibbolethCredentials* creds = dynamic_cast< ShibbolethCredentials* > (cfg.getCredentials());
if (!creds) {
qDebug() << "Not a Shibboleth creds instance!";
return 1;
}
ShibbolethRefresher refresher(creds, csync_ctx);
// blocks
refresher.refresh();
return creds->ready() ? 0 : 1;
}
} // ns
ShibbolethCredentials::ShibbolethCredentials()
: _shibCookie(),
_ready(false),
_browser(0),
_otherCookies()
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
: _shibCookie(cookie),
_ready(true),
_browser(0),
_otherCookies(otherCookies)
{}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
{
csync_set_auth_callback (ctx, handleNeonSSLProblems);
}
QByteArray ShibbolethCredentials::prepareCookieData() const
{
QString cookiesAsString;
// TODO: This should not be a part of this method, but we don't
// have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
QMap<QString, QString> uniqueCookies;
cookies << _shibCookie;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
const QString cookieName(c.name());
if (cookieName.startsWith("_shibsession_")) {
continue;
}
uniqueCookies.insert(cookieName, c.value());
}
if (!_shibCookie.name().isEmpty()) {
uniqueCookies.insert(_shibCookie.name(), _shibCookie.value());
}
foreach(const QString& cookieName, uniqueCookies.keys()) {
cookiesAsString += cookieName;
cookiesAsString += '=';
cookiesAsString += uniqueCookies[cookieName];
cookiesAsString += "; ";
}
return cookiesAsString.toLatin1();
}
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
{
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
csync_set_module_property(ctx, "redirect_callback", &cb);
}
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
{
ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials));
if (!other || other->cookie() != this->cookie()) {
return true;
}
return false;
}
QString ShibbolethCredentials::authType() const
{
return QString::fromLatin1("shibboleth");
}
QNetworkCookie ShibbolethCredentials::cookie() const
{
return _shibCookie;
}
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
{
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie));
connect(this, SIGNAL(newCookie(QNetworkCookie)),
qnam, SLOT(setCookie(QNetworkCookie)));
return qnam;
}
bool ShibbolethCredentials::ready() const
{
return _ready;
}
void ShibbolethCredentials::fetch()
{
if (_ready) {
Q_EMIT fetched();
} else {
ShibbolethConfigFile cfg;
_browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl()), cfg.createCookieJar());
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
connect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
_browser->show ();
}
}
void ShibbolethCredentials::persistForUrl(const QString& /*url*/)
{
ShibbolethConfigFile cfg;
cfg.storeCookies(_otherCookies);
}
void ShibbolethCredentials::disposeBrowser()
{
disconnect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
_browser->hide();
_browser->deleteLater();
_browser = 0;
}
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie)
{
disposeBrowser();
_ready = true;
_shibCookie = cookie;
Q_EMIT newCookie(_shibCookie);
Q_EMIT fetched();
}
void ShibbolethCredentials::slotBrowserHidden()
{
disposeBrowser();
_ready = false;
_shibCookie = QNetworkCookie();
Q_EMIT fetched();
}
void ShibbolethCredentials::invalidateAndFetch()
{
_ready = false;
connect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
fetch();
}
void ShibbolethCredentials::onFetched()
{
disconnect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
Q_EMIT invalidatedAndFetched(prepareCookieData());
}
} // ns Mirall
-72
Ver Arquivo
@@ -1,72 +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_CREDENTIALS_H
#define MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "creds/abstractcredentials.h"
namespace Mirall
{
class ShibbolethWebView;
class ShibbolethCredentials : public AbstractCredentials
{
Q_OBJECT
public:
ShibbolethCredentials();
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
void fetch();
void persistForUrl(const QString& url);
QNetworkCookie cookie() const;
public Q_SLOTS:
void invalidateAndFetch();
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie& cookie);
void slotBrowserHidden();
void onFetched();
Q_SIGNALS:
void newCookie(const QNetworkCookie& cookie);
void invalidatedAndFetched(const QByteArray& cookieData);
private:
QByteArray prepareCookieData() const;
void disposeBrowser();
QNetworkCookie _shibCookie;
bool _ready;
ShibbolethWebView* _browser;
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
};
} // ns Mirall
#endif
+7 -7
Ver Arquivo
@@ -23,12 +23,7 @@ int main(int argc, char **argv)
Mirall::Application app(argc, argv);
app.initialize();
if( app.giveHelp() ) {
app.showHelp();
return 0;
}
// if the application is already running, notify it.
if( app.isRunning() ) {
QStringList args = app.arguments();
@@ -48,6 +43,11 @@ int main(int argc, char **argv)
.arg(Mirall::Theme::instance()->appNameGUI()));
}
}
return app.exec();
// if help requested, show on command line and exit.
if( ! app.giveHelp() ) {
return app.exec();
} else {
app.showHelp();
}
}
-706
Ver Arquivo
@@ -1,706 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "accountsettings.h"
#include "ui_accountsettings.h"
#include "mirall/theme.h"
#include "mirall/folderman.h"
#include "mirall/owncloudinfo.h"
#include "mirall/folderwizard.h"
#include "mirall/folderstatusmodel.h"
#include "mirall/utility.h"
#include "mirall/application.h"
#include "mirall/owncloudsetupwizard.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/ignorelisteditor.h"
#include "mirall/itemprogressdialog.h"
#include <math.h>
#include <QDebug>
#include <QDesktopServices>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QAction>
#include <QKeySequence>
namespace Mirall {
static const char progressBarStyleC[] =
"QProgressBar {"
"border: 2px solid grey;"
"border-radius: 5px;"
"text-align: center;"
"}"
"QProgressBar::chunk {"
"background-color: %1; width: 1px;"
"}";
AccountSettings::AccountSettings(QWidget *parent) :
QWidget(parent),
ui(new Ui::AccountSettings),
_item(0)
{
ui->setupUi(this);
_model = new FolderStatusModel;
_model->setParent(this);
FolderStatusDelegate *delegate = new FolderStatusDelegate;
delegate->setParent(this);
ui->_folderList->setItemDelegate( delegate );
ui->_folderList->setModel( _model );
ui->_folderList->setMinimumWidth( 300 );
ui->_folderList->setEditTriggers( QAbstractItemView::NoEditTriggers );
ui->_ButtonRemove->setEnabled(false);
ui->_ButtonEnable->setEnabled(false);
ui->_ButtonInfo->setEnabled(false);
ui->_ButtonAdd->setEnabled(true);
QAction *resetFolderAction = new QAction(this);
resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5));
connect(resetFolderAction, SIGNAL(triggered()), SLOT(slotResetCurrentFolder()));
addAction(resetFolderAction);
connect(ui->_ButtonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveCurrentFolder()));
connect(ui->_ButtonEnable, SIGNAL(clicked()), this, SLOT(slotEnableCurrentFolder()));
connect(ui->_ButtonInfo, SIGNAL(clicked()), this, SLOT(slotInfoAboutCurrentFolder()));
connect(ui->_ButtonAdd, SIGNAL(clicked()), this, SLOT(slotAddFolder()));
connect(ui->modifyAccountButton, SIGNAL(clicked()), SLOT(slotOpenAccountWizard()));
connect(ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));;
connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex)));
connect(ui->_folderList, SIGNAL(doubleClicked(QModelIndex)),SLOT(slotDoubleClicked(QModelIndex)));
QColor color = palette().highlight().color();
ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
ownCloudInfo *ocInfo = ownCloudInfo::instance();
slotUpdateQuota(ocInfo->lastQuotaTotalBytes(), ocInfo->lastQuotaUsedBytes());
connect(ocInfo, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotUpdateQuota(qint64,qint64)));
ui->connectLabel->setWordWrap( true );
setFolderList(FolderMan::instance()->map());
slotCheckConnection();
}
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
{
bool state = indx.isValid();
ui->_ButtonRemove->setEnabled( state );
ui->_ButtonEnable->setEnabled( state );
ui->_ButtonInfo->setEnabled( state );
if ( state ) {
bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
qDebug() << "folder is sync enabled: " << folderEnabled;
if ( folderEnabled ) {
ui->_ButtonEnable->setText( tr( "Pause" ) );
} else {
ui->_ButtonEnable->setText( tr( "Resume" ) );
}
}
}
void AccountSettings::slotAddFolder()
{
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(false); // do not start more syncs.
FolderWizard *folderWizard = new FolderWizard(this);
Folder::Map folderMap = folderMan->map();
folderWizard->setFolderMap( folderMap );
connect(folderWizard, SIGNAL(accepted()), SLOT(slotFolderWizardAccepted()));
connect(folderWizard, SIGNAL(rejected()), SLOT(slotFolderWizardRejected()));
folderWizard->open();
}
void AccountSettings::slotFolderWizardAccepted()
{
FolderWizard *folderWizard = qobject_cast<FolderWizard*>(sender());
FolderMan *folderMan = FolderMan::instance();
qDebug() << "* Folder wizard completed";
QString alias = folderWizard->field(QLatin1String("alias")).toString();
QString sourceFolder = folderWizard->field(QLatin1String("sourceFolder")).toString();
QString targetPath = folderWizard->property("targetPath").toString();
if (!FolderMan::ensureJournalGone( sourceFolder ))
return;
folderMan->addFolderDefinition(alias, sourceFolder, targetPath );
Folder *f = folderMan->setupFolderFromConfigFile( alias );
slotAddFolder( f );
folderMan->setSyncEnabled(true);
if( f ) {
folderMan->slotScheduleAllFolders();
emit folderChanged();
}
buttonsSetEnabled();
}
void AccountSettings::slotFolderWizardRejected()
{
qDebug() << "* Folder wizard cancelled";
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(true);
folderMan->slotScheduleAllFolders();
}
void AccountSettings::slotOpenAccountWizard()
{
this->topLevelWidget()->close();
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), 0);
}
void AccountSettings::slotAddFolder( Folder *folder )
{
if( ! folder || folder->alias().isEmpty() ) return;
QStandardItem *item = new QStandardItem();
folderToModelItem( item, folder );
_model->appendRow( item );
slotCheckConnection();
}
void AccountSettings::buttonsSetEnabled()
{
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_ButtonRemove->setEnabled(false);
if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed.
ui->_ButtonAdd->setVisible(!haveFolders);
} else {
ui->_ButtonAdd->setVisible(true);
ui->_ButtonAdd->setEnabled(true);
}
QModelIndex selected = ui->_folderList->currentIndex();
bool isSelected = selected.isValid();
ui->_ButtonEnable->setEnabled(isSelected);
ui->_ButtonRemove->setEnabled(isSelected);
ui->_ButtonInfo->setEnabled(isSelected);
}
void AccountSettings::setListWidgetItem( QListWidgetItem *item )
{
_item = item;
}
void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
{
if( ! item || !f ) return;
item->setData( f->nativePath(), FolderStatusDelegate::FolderPathRole );
item->setData( f->secondPath(), FolderStatusDelegate::FolderSecondPathRole );
item->setData( f->alias(), FolderStatusDelegate::FolderAliasRole );
item->setData( f->syncEnabled(), FolderStatusDelegate::FolderSyncEnabled );
SyncResult res = f->syncResult();
SyncResult::Status status = res.status();
QStringList errorList = res.errorStrings();
QString errors;
if( ! errorList.isEmpty() ) {
errors = res.errorStrings().join(QLatin1String("<br/>"));
}
Theme *theme = Theme::instance();
item->setData( theme->statusHeaderText( status ), Qt::ToolTipRole );
if( f->syncEnabled() ) {
item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole );
} else {
item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before
}
item->setData( theme->statusHeaderText( status ), FolderStatusDelegate::FolderStatus );
item->setData( errors, FolderStatusDelegate::FolderErrorMsg );
if( errors.isEmpty() && (status == SyncResult::Error ||
status == SyncResult::SetupError ||
status == SyncResult::Unavailable )) {
item->setData( theme->statusHeaderText(status), FolderStatusDelegate::FolderErrorMsg);
}
bool ongoing = false;
item->setData( QVariant(res.warnCount()), FolderStatusDelegate::WarningCount );
if( status == SyncResult::SyncRunning ) {
ongoing = true;
}
item->setData( ongoing, FolderStatusDelegate::SyncRunning);
}
void AccountSettings::slotRemoveCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
qDebug() << "Remove Folder alias " << alias;
if( !alias.isEmpty() ) {
// remove from file system through folder man
// _model->removeRow( selected.row() );
int ret = QMessageBox::question( this, tr("Confirm Folder Remove"),
tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>"
"<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::No ) {
return;
}
FolderMan *folderMan = FolderMan::instance();
folderMan->slotRemoveFolder( alias );
setFolderList(folderMan->map());
emit folderChanged();
slotCheckConnection();
}
}
}
void AccountSettings::slotResetCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
int ret = QMessageBox::question( 0, tr("Confirm Folder Reset"),
tr("<p>Do you really want to reset folder <i>%1</i> and rebuild your client database?</p>"
"<p><b>Note:</b> This function is designed for maintenance purposes only. "
"No files will be removed, but this can cause significant data traffic and "
"take several minutes or hours to complete, depending on the size of the folder. "
"Only use this option if advised by your administrator.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::Yes ) {
FolderMan *folderMan = FolderMan::instance();
Folder *f = folderMan->folder(alias);
f->slotTerminateSync();
f->wipe();
folderMan->slotScheduleAllFolders();
}
}
}
void AccountSettings::slotDoubleClicked( const QModelIndex& indx )
{
if( ! indx.isValid() ) return;
QString alias = _model->data( indx, FolderStatusDelegate::FolderAliasRole ).toString();
emit openFolderAlias( alias );
}
void AccountSettings::slotCheckConnection()
{
if( ownCloudInfo::instance()->isConfigured() ) {
connect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
connect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotOCInfoFail(QNetworkReply*)));
ui->connectLabel->setText( tr("Checking %1 connection...").arg(Theme::instance()->appNameGUI()));
qDebug() << "Check status.php from statusdialog.";
ownCloudInfo::instance()->checkInstallation();
} else {
// ownCloud is not yet configured.
ui->connectLabel->setText( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()));
ui->_ButtonAdd->setEnabled( false);
}
}
void AccountSettings::setFolderList( const Folder::Map &folders )
{
_model->clear();
foreach( Folder *f, folders ) {
qDebug() << "Folder: " << f;
slotAddFolder( f );
}
QModelIndex idx = _model->index(0, 0);
if (idx.isValid()) {
ui->_folderList->setCurrentIndex(idx);
}
buttonsSetEnabled();
}
// move from Application
void AccountSettings::slotFolderOpenAction( const QString& alias )
{
Folder *f = FolderMan::instance()->folder(alias);
qDebug() << "opening local url " << f->path();
if( f ) {
QUrl url(f->path(), QUrl::TolerantMode);
url.setScheme( QLatin1String("file") );
#ifdef Q_OS_WIN32
// work around a bug in QDesktopServices on Win32, see i-net
QString filePath = f->path();
if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
url.setUrl(QDir::toNativeSeparators(filePath));
else
url = QUrl::fromLocalFile(filePath);
#endif
QDesktopServices::openUrl(url);
}
}
void AccountSettings::slotEnableCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
bool folderEnabled = _model->data( selected, FolderStatusDelegate::FolderSyncEnabled).toBool();
qDebug() << "Toggle enabled/disabled Folder alias " << alias << " - current state: " << folderEnabled;
if( !alias.isEmpty() ) {
FolderMan *folderMan = FolderMan::instance();
qDebug() << "Application: enable folder with alias " << alias;
bool terminate = false;
// this sets the folder status to disabled but does not interrupt it.
Folder *f = folderMan->folder( alias );
if( f && folderEnabled ) {
// check if a sync is still running and if so, ask if we should terminate.
if( f->isBusy() ) { // its still running
int reply = QMessageBox::question( 0, tr("Sync Running"),
tr("The syncing operation is running.<br/>Do you want to terminate it?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes );
if ( reply == QMessageBox::Yes )
terminate = true;
else
return; // do nothing
}
}
// message box can return at any time while the thread keeps running,
// so better check again after the user has responded.
if ( f->isBusy() && terminate )
folderMan->terminateSyncProcess( alias );
folderMan->slotEnableFolder( alias, !folderEnabled );
slotUpdateFolderState (f);
// set the button text accordingly.
slotFolderActivated( selected );
}
}
}
void AccountSettings::slotUpdateFolderState( Folder *folder )
{
QStandardItem *item = 0;
int row = 0;
if( ! folder ) return;
item = _model->item( row );
while( item ) {
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder->alias() ) {
// its the item to update!
break;
}
item = _model->item( ++row );
}
if( item ) {
folderToModelItem( item, folder );
} else {
// the dialog is not visible.
}
slotCheckConnection();
}
void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, const QString& version, const QString& )
{
#ifdef Q_OS_WIN32
// work around a bug in QDesktopServices on Win32, see i-net
QString filePath = url;
if (filePath.startsWith("\\\\") || filePath.startsWith("//"))
_OCUrl.setUrl(QDir::toNativeSeparators(filePath));
else
_OCUrl = QUrl::fromLocalFile(filePath);
#else
_OCUrl = QUrl::fromLocalFile(url);
#endif
qDebug() << "#-------# oC found on " << url;
/* enable the open button */
ui->connectLabel->setOpenExternalLinks(true);
QUrl safeUrl(url);
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
ui->connectLabel->setText( tr("Connected to <a href=\"%1\">%2</a>.").arg(url, safeUrl.toString()) );
ui->connectLabel->setToolTip( tr("Version: %1 (%2)").arg(versionStr).arg(version));
ui->_ButtonAdd->setEnabled(true);
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotOCInfoFail(QNetworkReply*)));
}
void AccountSettings::slotOCInfoFail( QNetworkReply *reply)
{
QString errStr = tr("unknown problem.");
if( reply ) errStr = reply->errorString();
ui->connectLabel->setText( tr("<p>Failed to connect to %1: <tt>%2</tt></p>").arg(Theme::instance()->appNameGUI()).arg(errStr) );
ui->_ButtonAdd->setEnabled( false);
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotOCInfoFail(QNetworkReply*)));
}
void AccountSettings::slotOpenOC()
{
if( _OCUrl.isValid() )
QDesktopServices::openUrl( _OCUrl );
}
QStandardItem* AccountSettings::itemForFolder(const QString& folder)
{
QStandardItem *item = NULL;
if( folder.isEmpty() ) {
return item;
}
int row = 0;
item = _model->item( row );
while( item ) {
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder ) {
// its the item to update!
break;
}
item = _model->item( ++row );
}
return item;
}
QString AccountSettings::shortenFilename( const QString& folder, const QString& file ) const
{
// strip off the server prefix from the file name
QString shortFile(file);
if( shortFile.isEmpty() ) {
return QString::null;
}
if(shortFile.startsWith(QLatin1String("ownclouds://")) ||
shortFile.startsWith(QLatin1String("owncloud://")) ) {
// rip off the whole ownCloud URL.
Folder *f = FolderMan::instance()->folder(folder);
if( f ) {
QString remotePathUrl = ownCloudInfo::instance()->webdavUrl() + QLatin1Char('/') + f->secondPath();
shortFile.remove(Utility::toCSyncScheme(remotePathUrl));
}
}
return shortFile;
}
void AccountSettings::slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem)
{
Q_UNUSED(problem);
QStandardItem *item = itemForFolder( folder );
if( !item ) return;
int warnCount = qvariant_cast<int>( item->data(FolderStatusDelegate::WarningCount) );
warnCount++;
item->setData( QVariant(warnCount), FolderStatusDelegate::WarningCount );
}
void AccountSettings::slotSetProgress(const QString& folder, const Progress::Info &progress )
{
// qDebug() << "================================> Progress for folder " << folder << " file " << file << ": "<< p1;
QStandardItem *item = itemForFolder( folder );
qint64 prog1 = progress.current_file_bytes;
qint64 prog2 = progress.file_size;
if( item == NULL ) {
return;
}
// Hotfix for a crash that I experienced in a very rare case/setup
if (progress.kind == Mirall::Progress::Invalid) {
qDebug() << "================================> INVALID Progress for folder " << folder;
return;
}
QString itemFileName = shortenFilename(folder, progress.current_file);
QString syncFileProgressString;
// stay with the previous kind-string for Context.
if( progress.kind != Progress::Context ) {
_kindContext = Progress::asActionString(progress.kind);
} else {
if( _kindContext.isEmpty() ) {
// empty kind context means that the dialog was opened after the action
// was started.
Progress::Kind kind = ProgressDispatcher::instance()->currentFolderContext(progress.folder);
if( kind != Progress::Invalid ) {
_kindContext = Progress::asActionString(kind);
}
}
}
QString kindString = _kindContext;
switch( progress.kind ) {
case Progress::StartSync:
item->setData( QVariant(0), FolderStatusDelegate::WarningCount );
break;
case Progress::StartDownload:
case Progress::StartUpload:
case Progress::StartDelete:
syncFileProgressString = tr("Start");
if( _hideProgressTimers.contains(item) ) {
// The timer is still running.
QTimer *t = _hideProgressTimers.take(item);
t->stop();
t->deleteLater();
}
break;
case Progress::Context:
syncFileProgressString = tr("Currently");
break;
case Progress::EndDownload:
case Progress::EndUpload:
case Progress::EndDelete:
break;
case Progress::EndSync:
syncFileProgressString = tr("Completely");
// start a timer to stop the progress display
QTimer *timer;
if( _hideProgressTimers.contains(item) ) {
timer = _hideProgressTimers[item];
// there is already one timer running.
} else {
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(slotHideProgress()));
timer->setSingleShot(true);
_hideProgressTimers.insert(item, timer);
}
timer->start(5000);
break;
case Progress::Invalid:
case Progress::Download:
case Progress::Upload:
case Progress::Inactive:
case Progress::Error:
break;
}
QString fileProgressString;
QString s1 = Utility::octetsToString( prog1 );
QString s2 = Utility::octetsToString( prog2 );
// switch on extra space.
item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace );
if( progress.kind != Progress::EndSync ) {
// Example text: "Currently uploading foobar.png (1MB of 2MB)"
fileProgressString = tr("%1 %2 %3 (%4 of %5)").arg(syncFileProgressString).arg(kindString).
arg(itemFileName).arg(s1).arg(s2);
} else {
fileProgressString = tr("Completely finished.");
}
item->setData( fileProgressString,FolderStatusDelegate::SyncProgressItemString);
// overall progress
s1 = Utility::octetsToString( progress.overall_current_bytes );
s2 = Utility::octetsToString( progress.overall_transmission_size );
QString overallSyncString = tr("%1 of %2, file %3 of %4").arg(s1).arg(s2)
.arg(progress.current_file_no).arg(progress.overall_file_count);
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
int overallPercent = 0;
if( progress.overall_transmission_size > 0 ) {
overallPercent = qRound(double(progress.overall_current_bytes)/double(progress.overall_transmission_size) * 100.0);
}
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
}
void AccountSettings::slotHideProgress()
{
QTimer *send_timer = qobject_cast<QTimer*>(this->sender());
QHash<QStandardItem*, QTimer*>::const_iterator i = _hideProgressTimers.constBegin();
while (i != _hideProgressTimers.constEnd()) {
if( i.value() == send_timer ) {
QStandardItem *item = i.key();
item->setData( QVariant(false), FolderStatusDelegate::AddProgressSpace );
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressOverallString );
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressItemString );
item->setData( 0, FolderStatusDelegate::SyncProgressOverallPercent );
ui->_folderList->repaint();
_hideProgressTimers.remove(item);
break;
}
++i;
}
send_timer->deleteLater();
}
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
{
ui->quotaProgressBar->setEnabled(true);
// workaround the label only accepting ints (which may be only 32 bit wide)
ui->quotaProgressBar->setMaximum(100);
int qVal = qRound(used/(double)total * 100);
if( qVal > 100 ) qVal = 100;
ui->quotaProgressBar->setValue(qVal);
QString usedStr = Utility::octetsToString(used);
QString totalStr = Utility::octetsToString(total);
ui->quotaLabel->setText(tr("%1 of %2 in use.").arg(usedStr, totalStr));
}
void AccountSettings::slotIgnoreFilesEditor()
{
if (_ignoreEditor.isNull()) {
_ignoreEditor = new IgnoreListEditor(this);
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
_ignoreEditor->open();
} else {
Utility::raiseDialog(_ignoreEditor);
}
}
void AccountSettings::slotInfoAboutCurrentFolder()
{
emit(openProgressDialog());
}
AccountSettings::~AccountSettings()
{
delete ui;
}
} // namespace Mirall
-107
Ver Arquivo
@@ -1,107 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef ACCOUNTSETTINGS_H
#define ACCOUNTSETTINGS_H
#include <QWidget>
#include <QUrl>
#include <QPointer>
#include <QHash>
#include <QTimer>
#include <QStandardItem>
#include "mirall/folder.h"
#include "mirall/progressdispatcher.h"
#include "mirall/itemprogressdialog.h"
class QStandardItemModel;
class QModelIndex;
class QStandardItem;
class QNetworkReply;
class QListWidgetItem;
namespace Mirall {
namespace Ui {
class AccountSettings;
}
class FolderMan;
class ItemProgressDialog;
class IgnoreListEditor;
class AccountSettings : public QWidget
{
Q_OBJECT
public:
explicit AccountSettings(QWidget *parent = 0);
~AccountSettings();
void setFolderList( const Folder::Map& );
void buttonsSetEnabled();
void setListWidgetItem(QListWidgetItem* item);
signals:
void folderChanged();
void openProgressDialog();
void openFolderAlias( const QString& );
void infoFolderAlias( const QString& );
public slots:
void slotFolderActivated( const QModelIndex& );
void slotOpenOC();
void slotUpdateFolderState( Folder* );
void slotCheckConnection();
void slotOCInfo( const QString&, const QString&, const QString&, const QString& );
void slotOCInfoFail( QNetworkReply* );
void slotDoubleClicked( const QModelIndex& );
void slotFolderOpenAction( const QString& );
void slotSetProgress(const QString&, const Progress::Info& progress);
void slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem);
void slotUpdateQuota( qint64,qint64 );
void slotIgnoreFilesEditor();
protected slots:
void slotAddFolder();
void slotAddFolder( Folder* );
void slotEnableCurrentFolder();
void slotRemoveCurrentFolder();
void slotInfoAboutCurrentFolder();
void slotResetCurrentFolder();
void slotFolderWizardAccepted();
void slotFolderWizardRejected();
void slotOpenAccountWizard();
void slotHideProgress();
private:
QString shortenFilename( const QString& folder, const QString& file ) const;
void folderToModelItem( QStandardItem *, Folder * );
QStandardItem* itemForFolder(const QString& );
Ui::AccountSettings *ui;
QPointer<ItemProgressDialog> _fileItemDialog;
QPointer<IgnoreListEditor> _ignoreEditor;
QStandardItemModel *_model;
QListWidgetItem *_item;
QUrl _OCUrl;
QHash<QStandardItem*, QTimer*> _hideProgressTimers;
QString _kindContext;
};
} // namespace Mirall
#endif // ACCOUNTSETTINGS_H
-150
Ver Arquivo
@@ -1,150 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::AccountSettings</class>
<widget class="QWidget" name="Mirall::AccountSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>382</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QGroupBox" name="maintenanceGroupBox">
<property name="title">
<string>Account Maintenance</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="ignoredFilesButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Edit Ignored Files</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="modifyAccountButton">
<property name="text">
<string>Modify Account</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="syncStatusGroupBox">
<property name="title">
<string>Sync Status</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="connectLabel">
<property name="text">
<string>Connected with &lt;server&gt; as &lt;user&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="_folderList"/>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="_ButtonAdd">
<property name="text">
<string>Add Folder...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonEnable">
<property name="text">
<string>Pause</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="_ButtonInfo">
<property name="text">
<string>Info...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="storageGroupBox">
<property name="title">
<string>Storage Usage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QProgressBar" name="quotaProgressBar">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="quotaLabel">
<property name="text">
<string>Retrieving usage information...</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;b&gt;Note:&lt;/b&gt; Some folders, including network mounted or shared folders, might have different limits.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+45 -45
Ver Arquivo
@@ -19,15 +19,15 @@
#include <QNetworkReply>
#include <QSslError>
#include <QPointer>
#include <QQueue>
#include "qtsingleapplication.h"
#include "mirall/syncresult.h"
#include "mirall/folder.h"
#include "mirall/logbrowser.h"
#include "mirall/folderman.h"
#include "mirall/fileitemdialog.h"
#include "mirall/systray.h"
#include "mirall/connectionvalidator.h"
#include "mirall/progressdispatcher.h"
class QAction;
class QMenu;
@@ -38,13 +38,13 @@ class QNetworkReply;
namespace Mirall {
class Theme;
class Folder;
class FolderWatcher;
class FolderWizard;
class StatusDialog;
class OwncloudSetupWizard;
class ownCloudInfo;
class SslErrorDialog;
class SettingsDialog;
class ItemProgressDialog;
class ProxyDialog;
class Application : public SharedTools::QtSingleApplication
{
@@ -56,11 +56,24 @@ public:
bool giveHelp();
void showHelp();
public slots:
// TODO: this should not be public
void slotownCloudWizardDone(int);
signals:
protected slots:
void slotAddFolder();
void slotOpenStatus();
void slotRemoveFolder( const QString& );
void slotResetFolder( const QString& );
void slotEnableFolder( const QString&, const bool );
void slotInfoFolder( const QString& );
void slotConfigure();
void slotConfigureProxy();
void slotParseOptions( const QString& );
void slotShowTrayMessage(const QString&, const QString&);
void slotSyncStateChange( const QString& );
void slotownCloudWizardDone(int);
protected:
void parseOptions(const QStringList& );
void setupTranslations();
void setupActions();
@@ -68,7 +81,6 @@ protected:
void setupContextMenu();
void setupLogBrowser();
void enterNextLogFile();
bool checkConfigExists(bool openSettings);
//folders have to be disabled while making config changes
void computeOverallSyncStatus();
@@ -78,69 +90,57 @@ protected:
bool winEventFilter( MSG * message, long * result );
#endif
signals:
void folderRemoved();
void folderStateChanged(Folder*);
protected slots:
void slotFoldersChanged();
void slotSettings();
void slotItemProgressDialog();
void slotParseOptions( const QString& );
void slotShowTrayMessage(const QString&, const QString&);
void slotShowOptionalTrayMessage(const QString&, const QString&);
void slotShowGuiMessage(const QString& title, const QString& message);
void slotCheckConnection();
void slotConnectionValidatorResult(ConnectionValidator::Status);
void slotSyncStateChange( const QString& );
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
void slotFolderOpenAction(const QString & );
void slotOpenOwnCloud();
void slotStartFolderSetup(int result = QDialog::Accepted); // defaulting to Accepted
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
void slotNoOwnCloudFound( QNetworkReply* );
void slotCheckAuthentication();
void slotAuthCheck( const QString& ,QNetworkReply* );
void slotOpenLogBrowser();
void slotAbout();
void slotSSLFailed( QNetworkReply *reply, QList<QSslError> errors );
void slotFetchCredentials();
void slotCredentialsFetched( bool );
void slotStartUpdateDetector();
void slotSetupProxy();
void slotRefreshQuotaDisplay( qint64 total, qint64 used );
void slotUseMonoIconsChanged( bool );
void slotUpdateProgress(const QString&, const Progress::Info&);
void slotProgressSyncProblem(const QString& folder, const Progress::SyncProblem &problem);
void slotDisplayIdle();
void slotHelp();
void slotCredentialsFetched();
private:
void setHelp();
void raiseDialog( QWidget* );
void rebuildRecentMenus();
void runValidator();
// configuration file -> folder
Systray *_tray;
QAction *_actionOpenoC;
QAction *_actionSettings;
QAction *_actionQuota;
QAction *_actionStatus;
QAction *_actionRecent;
QAction *_actionHelp;
QAction *_actionQuit;
QAction *_actionAddFolder;
QAction *_actionOpenStatus;
QAction *_actionConfigure;
QAction *_actionOpenoC;
QAction *_actionConfigureProxy;
QAction *_actionAbout;
#if QT_VERSION >= 0x040700
QNetworkConfigurationManager *_networkMgr;
#endif
QPointer<FolderWizard> _folderWizard;
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
SslErrorDialog *_sslErrorDialog;
ConnectionValidator *_conValidator;
// tray's menu
QMenu *_contextMenu;
QMenu *_recentActionsMenu;
StatusDialog *_statusDialog;
FileItemDialog *_fileItemDialog;
FolderMan *_folderMan;
Theme *_theme;
QSignalMapper *_folderOpenActionMapper;
LogBrowser *_logBrowser;
QPointer<SettingsDialog> _settingsDialog;
QPointer<ItemProgressDialog> _progressDialog;
QPointer<ProxyDialog> _proxyDialog;
QString _logFile;
QString _logDirectory;
int _logExpire;
bool _showLogWindow;
bool _logFlush;
+67 -40
Ver Arquivo
@@ -17,6 +17,7 @@
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "mirall/credentialstore.h"
namespace Mirall {
@@ -27,8 +28,7 @@ ConnectionValidator::ConnectionValidator(QObject *parent) :
}
ConnectionValidator::ConnectionValidator(const QString& connection, QObject *parent)
: QObject(parent),
_connection(connection)
:_connection(connection)
{
ownCloudInfo::instance()->setCustomConfigHandle(_connection);
}
@@ -38,42 +38,9 @@ QStringList ConnectionValidator::errors() const
return _errors;
}
QString ConnectionValidator::statusString( Status stat ) const
QString ConnectionValidator::statusString( Status )
{
QString re;
switch( stat ) {
case Undefined:
re = QLatin1String("Undefined");
break;
case Connected:
re = QLatin1String("Connected");
break;
case NotConfigured:
re = QLatin1String("NotConfigured");
break;
case ServerVersionMismatch:
re = QLatin1String("Server Version Mismatch");
break;
case CredentialsTooManyAttempts:
re = QLatin1String("Credentials Too Many Attempts");
break;
case CredentialError:
re = QLatin1String("CredentialError");
break;
case CredentialsUserCanceled:
re = QLatin1String("Credential User Canceled");
break;
case CredentialsWrong:
re = QLatin1String("Credentials Wrong");
break;
case StatusNotFound:
re = QLatin1String("Status not found");
break;
default:
re = QLatin1String("status undeclared.");
}
return re;
return QLatin1String("Get your street creds!");
}
@@ -93,7 +60,7 @@ void ConnectionValidator::checkConnection()
}
}
void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& /*edition*/)
void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& edition)
{
// status.php was found.
qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")";
@@ -115,7 +82,7 @@ void ConnectionValidator::slotStatusFound( const QString& url, const QString& ve
return;
}
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
QTimer::singleShot( 0, this, SLOT( slotFetchCredentials() ));
}
// status.php could not be loaded.
@@ -133,19 +100,77 @@ void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
}
void ConnectionValidator::slotFetchCredentials()
{
if( _connection.isEmpty() ) {
if( CredentialStore::instance()->canTryAgain() ) {
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
this, SLOT(slotCredentialsFetched(bool)) );
CredentialStore::instance()->fetchCredentials();
}
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
_errors << tr("Too many attempts to get a valid password.");
emit connectionResult( CredentialsTooManyAttempts );
}
} else {
// Pull credentials from Mirall config.
slotCredentialsFetched( true );
}
}
void ConnectionValidator::slotCredentialsFetched( bool ok )
{
qDebug() << "Credentials successfully fetched: " << ok;
disconnect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)) );
if( ! ok ) {
Status stat;
_errors << tr("Error: Could not retrieve the password!");
if( CredentialStore::instance()->state() == CredentialStore::UserCanceled ) {
_errors << tr("Password dialog was canceled!");
stat = CredentialsUserCanceled;
} else {
_errors << CredentialStore::instance()->errorMessage();
stat = CredentialError;
}
qDebug() << "Could not fetch credentials" << _errors;
emit connectionResult( stat );
} else {
QString user, pwd;
if( _connection.isEmpty() ) {
user = CredentialStore::instance()->user();
pwd = CredentialStore::instance()->password();
} else {
// in case of reconfiguration, the _connection is set.
MirallConfigFile cfg(_connection);
user = cfg.ownCloudUser();
pwd = cfg.ownCloudPasswd();
}
ownCloudInfo::instance()->setCredentials( user, pwd );
// Credential fetched ok.
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
}
}
void ConnectionValidator::slotCheckAuthentication()
{
connect( ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this, SLOT(slotAuthCheck(QString,QNetworkReply*)));
qDebug() << "# checking for authentication settings.";
ownCloudInfo::instance()->getWebDAVPath(QLatin1String("/") ); // this call needs to be authenticated.
ownCloudInfo::instance()->getRequest(QLatin1String("/"), true ); // this call needs to be authenticated.
// simply GET the webdav root, will fail if credentials are wrong.
// continue in slotAuthCheck here :-)
}
void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
{
bool ok = true;
Status stat = Connected;
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
@@ -153,6 +178,7 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
qDebug() << "******** Password is wrong!";
_errors << "The provided credentials are wrong.";
stat = CredentialsWrong;
ok = false;
}
// disconnect from ownCloud Info signals
@@ -160,6 +186,7 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
emit connectionResult( stat );
}
+5 -3
Ver Arquivo
@@ -45,12 +45,12 @@ public:
void checkConnection();
QString statusString( Status ) const;
QString statusString( Status );
signals:
void connectionResult( ConnectionValidator::Status );
// void connectionAvailable();
// void connectionFailed();
void connectionAvailable();
void connectionFailed();
public slots:
@@ -58,6 +58,8 @@ protected slots:
void slotStatusFound( const QString&, const QString&, const QString&, const QString& );
void slotNoStatusFound(QNetworkReply *);
void slotFetchCredentials();
void slotCredentialsFetched( bool );
void slotCheckAuthentication();
void slotAuthCheck( const QString& ,QNetworkReply * );
@@ -16,8 +16,8 @@
#include "config.h"
#include "creds/http/credentialstore.h"
#include "creds/http/httpconfigfile.h"
#include "mirall/credentialstore.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#ifdef WITH_QTKEYCHAIN
@@ -35,6 +35,7 @@ QString CredentialStore::_passwd = QString::null;
QString CredentialStore::_user = QString::null;
QString CredentialStore::_url = QString::null;
QString CredentialStore::_errorMsg = QString::null;
int CredentialStore::_tries = 0;
#ifdef WITH_QTKEYCHAIN
CredentialStore::CredentialType CredentialStore::_type = KeyChain;
#else
@@ -66,14 +67,39 @@ CredentialStore::CredState CredentialStore::state()
return _state;
}
bool CredentialStore::canTryAgain()
{
if( _tries > MAX_LOGIN_ATTEMPTS ) {
qDebug() << "canTryAgain: Max attempts reached.";
return false;
}
/* Since QtKeyChain is required now, it makes sense to only query once. */
if( _state == NotFetched || _state == AsyncWriting ) {
return true;
} else {
return false;
}
}
void CredentialStore::fetchCredentials()
{
HttpConfigFile cfgFile;
MirallConfigFile cfgFile;
if( ++_tries > MAX_LOGIN_ATTEMPTS ) {
qDebug() << "Too many attempts to enter password!";
_state = TooManyAttempts;
emit( fetchCredentialsFinished(false) );
return;
}
bool ok = false;
QString pwd;
_user = cfgFile.user();
_user = cfgFile.ownCloudUser();
_url = cfgFile.ownCloudUrl();
if( !cfgFile.passwordStorageAllowed() ) {
_type = CredentialStore::User;
}
QString key = keyChainKey(_url);
@@ -85,17 +111,26 @@ void CredentialStore::fetchCredentials()
}
switch( _type ) {
case CredentialStore::User: {
/* Ask the user for the password */
/* Fixme: Move user interaction out here. */
_state = AsyncFetching;
_inputDialog = new QInputDialog;
_inputDialog->setWindowTitle(QApplication::translate("MirallConfigFile","Password Required") );
_inputDialog->setLabelText( QApplication::translate("MirallConfigFile","Please enter your %1 password:")
.arg(Theme::instance()->appNameGUI()));
_inputDialog->setInputMode( QInputDialog::TextInput );
_inputDialog->setTextEchoMode( QLineEdit::Password );
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
_inputDialog->open();
break;
}
case CredentialStore::Settings: {
/* Read from config file. */
_state = Fetching;
cfgFile.fixupOldPassword();
if( cfgFile.passwordExists() ) {
pwd = cfgFile.password();
ok = true;
} else {
ok = false;
_state = EntryNotFound;
}
pwd = cfgFile.ownCloudPasswd();
ok = true;
break;
}
case CredentialStore::KeyChain: {
@@ -142,11 +177,25 @@ void CredentialStore::fetchCredentials()
}
}
void CredentialStore::slotUserDialogDone( int result )
{
if( result == QDialog::Accepted ) {
_passwd = _inputDialog->textValue();
_state = Ok;
} else {
_state = UserCanceled;
_passwd = QString::null;
}
_inputDialog->deleteLater();
emit(fetchCredentialsFinished(_state == Ok));
}
void CredentialStore::reset()
{
_state = NotFetched;
_user = QString::null;
_passwd = QString::null;
_tries = 0;
}
QString CredentialStore::keyChainKey( const QString& url ) const
@@ -193,6 +242,9 @@ void CredentialStore::slotKeyChainReadFinished(QKeychain::Job* job)
case QKeychain::CouldNotDeleteEntry:
_state = Error;
break;
case QKeychain::AccessDeniedByUser:
_state = AccessDeniedByUser;
break;
case QKeychain::AccessDenied:
_state = AccessDenied;
break;
@@ -241,36 +293,43 @@ QString CredentialStore::errorMessage()
}
void CredentialStore::setCredentials( const QString& url, const QString& user,
const QString& pwd )
const QString& pwd, bool allowToStore )
{
_passwd = pwd;
_user = user;
if( allowToStore ) {
#ifdef WITH_QTKEYCHAIN
_type = KeyChain;
_type = KeyChain;
#else
_type = Settings;
_type = Settings;
#endif
} else {
_type = User;
}
_url = url;
_state = Ok;
}
void CredentialStore::saveCredentials( )
{
HttpConfigFile cfgFile;
MirallConfigFile cfgFile;
QString key = keyChainKey(_url);
if( key.isNull() ) {
qDebug() << "Error: Can not save credentials, URL is zero!";
return;
}
#ifdef WITH_QTKEYCHAIN
WritePasswordJob *job = NULL;
#endif
cfgFile.setUser(_user);
switch( _type ) {
case CredentialStore::KeyChain: {
case CredentialStore::User:
deleteKeyChainCredential( key );
break;
case CredentialStore::KeyChain:
#ifdef WITH_QTKEYCHAIN
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
// Set password in KeyChain
job = new WritePasswordJob(Theme::instance()->appName());
job->setKey( key );
job->setTextData(_passwd);
@@ -279,10 +338,9 @@ void CredentialStore::saveCredentials( )
_state = AsyncWriting;
job->start();
#endif
}
break;
case CredentialStore::Settings:
cfgFile.setPassword( _passwd );
cfgFile.writePassword( _passwd );
reset();
break;
default:
@@ -311,9 +369,10 @@ void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job )
} else {
qDebug() << "Successfully stored password for user " << _user;
// Try to remove password formerly stored in the config file.
HttpConfigFile cfgFile;
cfgFile.removePassword();
MirallConfigFile cfgFile;
cfgFile.clearPasswordFromConfig();
_state = NotFetched;
_tries = 0;
}
} else {
qDebug() << "Error: KeyChain Write Password Job failed!";
@@ -34,8 +34,10 @@ namespace Mirall {
* The fetchCredentials() call changes the internal state of the credential store
* to one of
* Ok: There are credentials. Note that it's unknown if they are correct!!
* UserCanceled: The fetching involved user interaction and the user canceled
* the operation. No valid credentials are there.
* TooManyAttempts: The user tried to often to enter a password.
* Fetching: The fetching is not yet finished.
* EntryNotFound: No password entry found in the storage.
* Error: A general error happened.
* After fetching has finished, signal fetchCredentialsFinished(bool) is emitted.
* The result can be retrieved with state() and password() and user() methods.
@@ -47,16 +49,20 @@ class CredentialStore : public QObject
public:
enum CredState { NotFetched = 0,
Ok,
UserCanceled,
Fetching,
AsyncFetching,
EntryNotFound,
AccessDeniedByUser,
AccessDenied,
NoKeychainBackend,
Error,
AsyncWriting };
AsyncWriting,
TooManyAttempts };
enum CredentialType {
Settings = 0,
User = 0,
Settings,
KeyChain
};
@@ -91,13 +97,19 @@ public:
* The function also sets the state to ok.
* @param url - the connection url
* @param user - the user name
* @param password - the password.
*/
void setCredentials( const QString& url, const QString& user, const QString& pwd);
void setCredentials( const QString&, const QString&, const QString&, bool );
void saveCredentials( );
QString errorMessage();
/**
* @brief canTryAgain - check if another try to get credentials makes sense.
*/
bool canTryAgain();
void reset();
signals:
/**
@@ -113,6 +125,7 @@ signals:
protected slots:
void slotKeyChainReadFinished( QKeychain::Job* );
void slotKeyChainWriteFinished( QKeychain::Job* );
void slotUserDialogDone(int);
private:
explicit CredentialStore(QObject *parent = 0);
@@ -125,7 +138,9 @@ private:
static QString _user;
static QString _url;
static QString _errorMsg;
static int _tries;
static CredentialType _type;
QInputDialog *_inputDialog;
};
}
+55 -174
Ver Arquivo
@@ -18,7 +18,6 @@
#include "mirall/theme.h"
#include "mirall/logger.h"
#include "mirall/owncloudinfo.h"
#include "creds/abstractcredentials.h"
#ifdef Q_OS_WIN
#include <windows.h>
@@ -61,100 +60,97 @@ CSyncThread::~CSyncThread()
//Convert an error code from csync to a user readable string.
// Keep that function thread safe as it can be called from the sync thread or the main thread
QString CSyncThread::csyncErrorToString(CSYNC_STATUS err, const char *errString )
QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errString )
{
QString errStr;
switch( err ) {
case CSYNC_STATUS_OK:
case CSYNC_ERR_NONE:
errStr = tr("Success.");
break;
case CSYNC_STATUS_NO_LOCK:
case CSYNC_ERR_LOG:
errStr = tr("CSync Logging setup failed.");
break;
case CSYNC_ERR_LOCK:
errStr = tr("CSync failed to create a lock file.");
break;
case CSYNC_STATUS_STATEDB_LOAD_ERROR:
case CSYNC_ERR_STATEDB_LOAD:
errStr = tr("CSync failed to load the state db.");
break;
case CSYNC_STATUS_STATEDB_WRITE_ERROR:
errStr = tr("CSync failed to write the state db.");
break;
case CSYNC_STATUS_NO_MODULE:
case CSYNC_ERR_MODULE:
errStr = tr("<p>The %1 plugin for csync could not be loaded.<br/>Please verify the installation!</p>").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_TIMESKEW:
case CSYNC_ERR_TIMESKEW:
errStr = tr("The system time on this client is different than the system time on the server. "
"Please use a time synchronization service (NTP) on the server and client machines "
"so that the times remain the same.");
break;
case CSYNC_STATUS_FILESYSTEM_UNKNOWN:
case CSYNC_ERR_FILESYSTEM:
errStr = tr("CSync could not detect the filesystem type.");
break;
case CSYNC_STATUS_TREE_ERROR:
case CSYNC_ERR_TREE:
errStr = tr("CSync got an error while processing internal trees.");
break;
case CSYNC_STATUS_MEMORY_ERROR:
case CSYNC_ERR_MEM:
errStr = tr("CSync failed to reserve memory.");
break;
case CSYNC_STATUS_PARAM_ERROR:
case CSYNC_ERR_PARAM:
errStr = tr("CSync fatal parameter error.");
break;
case CSYNC_STATUS_UPDATE_ERROR:
case CSYNC_ERR_UPDATE:
errStr = tr("CSync processing step update failed.");
break;
case CSYNC_STATUS_RECONCILE_ERROR:
case CSYNC_ERR_RECONCILE:
errStr = tr("CSync processing step reconcile failed.");
break;
case CSYNC_STATUS_PROPAGATE_ERROR:
case CSYNC_ERR_PROPAGATE:
errStr = tr("CSync processing step propagate failed.");
break;
case CSYNC_STATUS_REMOTE_ACCESS_ERROR:
case CSYNC_ERR_ACCESS_FAILED:
errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>");
break;
case CSYNC_STATUS_REMOTE_CREATE_ERROR:
case CSYNC_STATUS_REMOTE_STAT_ERROR:
case CSYNC_ERR_REMOTE_CREATE:
case CSYNC_ERR_REMOTE_STAT:
errStr = tr("A remote file can not be written. Please check the remote access.");
break;
case CSYNC_STATUS_LOCAL_CREATE_ERROR:
case CSYNC_STATUS_LOCAL_STAT_ERROR:
case CSYNC_ERR_LOCAL_CREATE:
case CSYNC_ERR_LOCAL_STAT:
errStr = tr("The local filesystem can not be written. Please check permissions.");
break;
case CSYNC_STATUS_PROXY_ERROR:
case CSYNC_ERR_PROXY:
errStr = tr("CSync failed to connect through a proxy.");
break;
case CSYNC_STATUS_PROXY_AUTH_ERROR:
errStr = tr("CSync could not authenticate at the proxy.");
break;
case CSYNC_STATUS_LOOKUP_ERROR:
case CSYNC_ERR_LOOKUP:
errStr = tr("CSync failed to lookup proxy or server.");
break;
case CSYNC_STATUS_SERVER_AUTH_ERROR:
case CSYNC_ERR_AUTH_SERVER:
errStr = tr("CSync failed to authenticate at the %1 server.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_CONNECT_ERROR:
case CSYNC_ERR_AUTH_PROXY:
errStr = tr("CSync failed to authenticate at the proxy.");
break;
case CSYNC_ERR_CONNECT:
errStr = tr("CSync failed to connect to the network.");
break;
case CSYNC_STATUS_TIMEOUT:
case CSYNC_ERR_TIMEOUT:
errStr = tr("A network connection timeout happend.");
break;
case CSYNC_STATUS_HTTP_ERROR:
case CSYNC_ERR_HTTP:
errStr = tr("A HTTP transmission error happened.");
break;
case CSYNC_STATUS_PERMISSION_DENIED:
case CSYNC_ERR_PERM:
errStr = tr("CSync failed due to not handled permission deniend.");
break;
case CSYNC_STATUS_NOT_FOUND:
case CSYNC_ERR_NOT_FOUND:
errStr = tr("CSync failed to find a specific file.");
break;
case CSYNC_STATUS_FILE_EXISTS:
case CSYNC_ERR_EXISTS:
errStr = tr("CSync tried to create a directory that already exists.");
break;
case CSYNC_STATUS_OUT_OF_SPACE:
case CSYNC_ERR_NOSPC:
errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_QUOTA_EXCEEDED:
errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_UNSUCCESSFUL:
case CSYNC_ERR_UNSPEC:
errStr = tr("CSync unspecified error.");
default:
@@ -236,20 +232,6 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
break;
}
switch( file->type ) {
case CSYNC_FTW_TYPE_DIR:
item._type = SyncFileItem::Directory;
break;
case CSYNC_FTW_TYPE_FILE:
item._type = SyncFileItem::File;
break;
case CSYNC_FTW_TYPE_SLINK:
item._type = SyncFileItem::SoftLink;
break;
default:
item._type = SyncFileItem::UnknownType;
}
item._dir = dir;
_mutex.lock();
_syncedItems.append(item);
@@ -260,7 +242,7 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
int CSyncThread::treewalkError(TREE_WALK_FILE* file)
{
SyncFileItem item; // only used for search.
SyncFileItem item;
item._file= QString::fromUtf8(file->path);
int indx = _syncedItems.indexOf(item);
@@ -269,10 +251,9 @@ int CSyncThread::treewalkError(TREE_WALK_FILE* file)
if( file &&
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
_mutex.lock();
_syncedItems[indx]._instruction = file->instruction;
_syncedItems[indx]._errorString = QString::fromUtf8(file->error_string);
_mutex.unlock();
}
@@ -298,15 +279,16 @@ struct CSyncRunScopeHelper {
};
void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) {
int err = csync_get_status( ctx );
const char *errMsg = csync_get_status_string( ctx );
QString errStr = csyncErrorToString( (CSYNC_STATUS)err, errMsg);
CSYNC_ERROR_CODE err = csync_get_error( ctx );
const char *errMsg = csync_get_error_string( ctx );
QString errStr = csyncErrorToString(err, errMsg);
qDebug() << " #### ERROR during "<< state << ": " << errStr;
if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_SERVICE_UNAVAILABLE ) ||
CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_CONNECT_ERROR )) {
switch (err) {
case CSYNC_ERR_SERVICE_UNAVAILABLE:
case CSYNC_ERR_CONNECT:
emit csyncUnavailable();
} else {
break;
default:
emit csyncError(errStr);
}
}
@@ -333,50 +315,11 @@ void CSyncThread::startSync()
// cleans up behind us and emits finished() to ease error handling
CSyncRunScopeHelper helper(_csync_ctx, this);
// maybe move this somewhere else where it can influence a running sync?
MirallConfigFile cfg;
int downloadLimit = 0;
if (cfg.useDownloadLimit()) {
downloadLimit = cfg.downloadLimit() * 1000;
}
csync_set_module_property(_csync_ctx, "bandwidth_limit_download", &downloadLimit);
int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
if ( useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
csync_set_module_property(_csync_ctx, "bandwidth_limit_upload", &uploadLimit);
csync_set_progress_callback( _csync_ctx, cb_progress );
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
csync_set_userdata(_csync_ctx, this);
// TODO: This should be a part of this method, but we don't have
// any way to get "session_key" module property from csync. Had we
// have it, then we could keep this code and remove it from
// AbstractCredentials implementations.
cfg.getCredentials()->syncContextPreStart(_csync_ctx);
// if (_lastAuthCookies.length() > 0) {
// // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// // when https://github.com/owncloud/core/pull/4042 is merged.
// QString cookiesAsString;
// foreach(QNetworkCookie c, _lastAuthCookies) {
// cookiesAsString += c.name();
// cookiesAsString += '=';
// cookiesAsString += c.value();
// cookiesAsString += "; ";
// }
// csync_set_module_property(_csync_ctx, "session_key", cookiesAsString.to
// }
// csync_set_auth_callback( _csync_ctx, getauth );
csync_set_progress_callback( _csync_ctx, progress );
qDebug() << "#### Update start #################################################### >>";
if( csync_update(_csync_ctx) < 0 ) {
@@ -386,7 +329,7 @@ void CSyncThread::startSync()
qDebug() << "<<#### Update end ###########################################################";
if( csync_reconcile(_csync_ctx) < 0 ) {
handleSyncError(_csync_ctx, "csync_reconcile");
handleSyncError(_csync_ctx, "cysnc_reconcile");
return;
}
@@ -420,7 +363,7 @@ void CSyncThread::startSync()
if( walkOk ) {
if( csync_walk_local_tree(_csync_ctx, &walkFinalize, 0) < 0 ||
csync_walk_remote_tree(_csync_ctx, &walkFinalize, 0 ) < 0 ) {
csync_walk_remote_tree( _csync_ctx, &walkFinalize, 0 ) < 0 ) {
qDebug() << "Error in finalize treewalk.";
} else {
// emit the treewalk results.
@@ -430,78 +373,16 @@ void CSyncThread::startSync()
qDebug() << Q_FUNC_INFO << "Sync finished";
}
Progress::Kind CSyncThread::csyncToProgressKind( enum csync_notify_type_e kind )
void CSyncThread::progress(const char *remote_url, enum csync_notify_type_e kind,
long long o1, long long o2, void *userdata)
{
Progress::Kind pKind = Progress::Invalid;
switch(kind) {
case CSYNC_NOTIFY_INVALID:
pKind = Progress::Invalid;
break;
case CSYNC_NOTIFY_START_SYNC_SEQUENCE:
pKind = Progress::StartSync;
break;
case CSYNC_NOTIFY_START_DOWNLOAD:
pKind = Progress::StartDownload;
break;
case CSYNC_NOTIFY_START_UPLOAD:
pKind = Progress::StartUpload;
break;
case CSYNC_NOTIFY_PROGRESS:
pKind = Progress::Context;
break;
case CSYNC_NOTIFY_FINISHED_DOWNLOAD:
pKind = Progress::EndDownload;
break;
case CSYNC_NOTIFY_FINISHED_UPLOAD:
pKind = Progress::EndUpload;
break;
case CSYNC_NOTIFY_FINISHED_SYNC_SEQUENCE:
pKind = Progress::EndSync;
break;
case CSYNC_NOTIFY_START_DELETE:
pKind = Progress::StartDelete;
break;
case CSYNC_NOTIFY_END_DELETE:
pKind = Progress::EndDelete;
break;
case CSYNC_NOTIFY_ERROR:
pKind = Progress::Error;
break;
default:
pKind = Progress::Invalid;
break;
(void) o1; (void) o2;
if (kind == CSYNC_NOTIFY_FINISHED_DOWNLOAD) {
QString path = QUrl::fromEncoded(remote_url).toString();
CSyncThread *thread = static_cast<CSyncThread*>(userdata);
thread->fileReceived(path);
}
return pKind;
}
void CSyncThread::cb_progress( CSYNC_PROGRESS *progress, void *userdata )
{
if( !progress ) {
qDebug() << "No progress block in progress callback found!";
return;
}
if( !userdata ) {
qDebug() << "No thread given in progress callback!";
return;
}
Progress::Info pInfo;
CSyncThread *thread = static_cast<CSyncThread*>(userdata);
pInfo.kind = thread->csyncToProgressKind( progress->kind );
pInfo.current_file = QUrl::fromEncoded( progress->path ).toString();
pInfo.file_size = progress->file_size;
pInfo.current_file_bytes = progress->curr_bytes;
pInfo.overall_file_count = progress->overall_file_count;
pInfo.current_file_no = progress->current_file_no;
pInfo.overall_transmission_size = progress->overall_transmission_size;
pInfo.overall_current_bytes = progress->current_overall_bytes;
pInfo.timestamp = QDateTime::currentDateTime();
// Connect to something in folder!
thread->transmissionProgress( pInfo );
}
} // ns Mirall
+6 -8
Ver Arquivo
@@ -22,12 +22,10 @@
#include <QThread>
#include <QString>
#include <QNetworkProxy>
#include <QNetworkCookie>
#include <csync.h>
#include "mirall/syncfileitem.h"
#include "mirall/progressdispatcher.h"
class QProcess;
@@ -40,7 +38,7 @@ public:
CSyncThread(CSYNC *);
~CSyncThread();
static QString csyncErrorToString( CSYNC_STATUS, const char * );
static QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
Q_INVOKABLE void startSync();
@@ -52,7 +50,6 @@ signals:
void csyncUnavailable();
void treeWalkResult(const SyncFileItemVector&);
void transmissionProgress( const Progress::Info& progress );
void csyncStateDbFile( const QString& );
void wipeDb();
@@ -63,15 +60,16 @@ signals:
private:
void handleSyncError(CSYNC *ctx, const char *state);
static void cb_progress( CSYNC_PROGRESS *progress, void *userdata );
static void progress(const char *remote_url,
enum csync_notify_type_e kind,
long long o1, long long o2,
void *userdata);
static int treewalkLocal( TREE_WALK_FILE*, void *);
static int treewalkRemote( TREE_WALK_FILE*, void *);
int treewalkFile( TREE_WALK_FILE*, bool );
int treewalkError( TREE_WALK_FILE* );
Progress::Kind csyncToProgressKind( enum csync_notify_type_e kind );
static int walkFinalize(TREE_WALK_FILE*, void* );
@@ -85,7 +83,7 @@ private:
bool _hasFiles; // true if there is at least one file that is not ignored or removed
friend struct CSyncRunScopeHelper;
friend class CSyncRunScopeHelper;
};
}
+304
Ver Arquivo
@@ -0,0 +1,304 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QtGui>
#include "mirall/fileitemdialog.h"
#include "mirall/theme.h"
#include "mirall/syncresult.h"
#include "mirall/logger.h"
#define TYPE_SUCCESS 1
#define TYPE_CONFLICT 2
#define TYPE_NEW 3
#define TYPE_DELETED 4
#define TYPE_ERROR 5
#define TYPE_RENAME 6
#define TYPE_IGNORE 7
#define FILE_TYPE 100
namespace Mirall {
FileItemDialog::FileItemDialog(Theme *theme, QWidget *parent) :
QDialog(parent),
_theme(theme)
{
setupUi(this);
connect(_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(accept()));
QStringList header;
header << tr("Files");
QString firstColString = tr("File Count");
header << firstColString;
_treeWidget->setHeaderLabels( header );
_treeWidget->setColumnWidth(0, 480);
_timer.setInterval(1000);
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotSetFolderMessage()));
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
QPushButton *copyBtn = _dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
setWindowTitle(tr("Sync Protocol"));
}
void FileItemDialog::setSyncResult( const SyncResult& result )
{
QString folderMessage;
SyncResult::Status syncStatus = result.status();
switch( syncStatus ) {
case SyncResult::Undefined:
folderMessage = tr( "Undefined Folder State" );
break;
case SyncResult::NotYetStarted:
folderMessage = tr( "The folder waits to start syncing." );
break;
case SyncResult::SyncPrepare:
folderMessage = tr( "Determining which files to sync." );
break;
case SyncResult::Unavailable:
folderMessage = tr( "Server is currently not available." );
break;
case SyncResult::SyncRunning:
folderMessage = tr("Sync is running.");
break;
case SyncResult::Success:
folderMessage = tr("Last Sync was successful.");
break;
case SyncResult::Error:
folderMessage = tr( "Syncing Error." );
break;
case SyncResult::SetupError:
folderMessage = tr( "Setup Error." );
break;
default:
folderMessage = tr( "Undefined Error State." );
}
_folderMessage = folderMessage;
_lastSyncTime = result.syncTime();
if( result.errorStrings().count() ) {
_errorLabel->setVisible(true);
_errorLabel->setTextFormat(Qt::RichText);
QString errStr;
foreach( QString err, result.errorStrings() ) {
errStr.append(QString("<p>%1</p>").arg(err));
}
_errorLabel->setText(errStr);
} else {
_errorLabel->setText(QString::null);
_errorLabel->setVisible(false);
}
slotSetFolderMessage();
if( syncStatus == SyncResult::SyncRunning ) {
_timer.stop();
} else {
_timer.start();
}
setSyncFileItems( result.syncFileItemVector() );
}
void FileItemDialog::slotSetFolderMessage()
{
QDateTime now = QDateTime::currentDateTime();
int secs = _lastSyncTime.secsTo(now);
if (secs < 60)
_timelabel->setText(tr("%1 (last finished %n sec. ago)", "", secs).arg(_folderMessage));
else
_timelabel->setText(tr("%1 (last finished %n min. ago)", "", secs/60).arg(_folderMessage));
}
void FileItemDialog::copyToClipboard()
{
QString text;
QTextStream ts(&text);
int topLevelItems = _treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *item = _treeWidget->topLevelItem(i);
ts << left << qSetFieldWidth(50)
<< item->data(0, Qt::DisplayRole).toString()
<< right << qSetFieldWidth(6)
<< item->data(1, Qt::DisplayRole).toString()
<< endl;
int childItems = item->childCount();
for (int j = 0; j < childItems; j++) {
QTreeWidgetItem *child =item->child(j);
ts << left << qSetFieldWidth(0) << QLatin1String(" ")
<< child->data(0,Qt::DisplayRole).toString()
<< QString::fromLatin1(" (%1)").arg(
child->data(1, Qt::DisplayRole).toString()
)
<< endl;
}
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
}
void FileItemDialog::accept()
{
_timer.stop();
QDialog::accept();
}
void FileItemDialog::setSyncFileItems( const SyncFileItemVector& list )
{
_treeWidget->clear();
QStringList strings;
QFont headerFont;
headerFont.setWeight(QFont::Bold);
strings.clear();
strings.append(tr("Synced Files"));
_syncedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_SUCCESS );
_syncedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_syncedFileItem);
strings.clear();
strings.append(tr("New Files"));
_newFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_NEW );
_newFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_newFileItem);
strings.clear();
strings.append(tr("Deleted Files"));
_deletedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_DELETED );
_deletedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_deletedFileItem);
strings.clear();
strings.append(tr("Renamed Files"));
_renamedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_RENAME);
_renamedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_renamedFileItem);
strings.clear();
strings.append(tr("Ignored Files"));
_ignoredFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_IGNORE);
_ignoredFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_renamedFileItem);
strings.clear();
strings.append(tr("Errors"));
_errorFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_ERROR );
_errorFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_errorFileItem);
strings.clear();
strings.append(tr("Conflicts"));
_conflictFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_CONFLICT);
_conflictFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_conflictFileItem);
QList<QTreeWidgetItem*> syncedItems;
QList<QTreeWidgetItem*> renamedItems;
QList<QTreeWidgetItem*> newItems;
QList<QTreeWidgetItem*> deletedItems;
QList<QTreeWidgetItem*> ignoredItems;
QList<QTreeWidgetItem*> conflictItems;
QList<QTreeWidgetItem*> errorItems;
quint64 overall_files = 0;
foreach( SyncFileItem item, list ) {
overall_files++;
QString dir;
QStringList str( item._file );
if( item._dir == SyncFileItem::Up ) dir = tr("Uploaded");
if( item._dir == SyncFileItem::Down ) dir = tr("Downloaded");
str << dir;
switch( item._instruction ) {
case CSYNC_INSTRUCTION_NONE:
// do nothing.
break;
case CSYNC_INSTRUCTION_EVAL:
// should not happen
break;
case CSYNC_INSTRUCTION_REMOVE:
case CSYNC_INSTRUCTION_DELETED:
deletedItems.append( new QTreeWidgetItem(_deletedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_RENAME:
renamedItems.append( new QTreeWidgetItem(_renamedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_NEW:
newItems.append( new QTreeWidgetItem(_newFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_CONFLICT:
conflictItems.append( new QTreeWidgetItem(_conflictFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_IGNORE:
ignoredItems.append( new QTreeWidgetItem(_ignoredFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_UPDATED:
syncedItems.append( new QTreeWidgetItem(_syncedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_STAT_ERROR:
case CSYNC_INSTRUCTION_ERROR:
errorItems.append( new QTreeWidgetItem(_errorFileItem, str, FILE_TYPE) );
break;
default:
break;
}
}
formatHeaderItem( _syncedFileItem, syncedItems );
formatHeaderItem( _newFileItem, newItems );
formatHeaderItem( _deletedFileItem, deletedItems );
formatHeaderItem( _renamedFileItem, renamedItems );
formatHeaderItem( _errorFileItem, errorItems );
formatHeaderItem( _conflictFileItem, conflictItems );
formatHeaderItem( _ignoredFileItem, ignoredItems );
}
void FileItemDialog::formatHeaderItem( QTreeWidgetItem *header, const QList<QTreeWidgetItem*>& list )
{
if( !header ) return;
header->addChildren( list );
int count = list.count();
#if LEAVE_THAT_TO_DESIGNERS
QColor col("#adc5d3");
header->setBackgroundColor(0, col);
header->setBackgroundColor(1, col);
#endif
header->setText(1, QString::number( count ));
if( count ) {
QFont font;
font.setWeight( QFont::Bold );
header->setFont(0, font);
header->setFont(1, font);
header->setExpanded(true);
} else {
header->setExpanded(false);
}
}
}
@@ -16,51 +16,52 @@
#include <QDialog>
#include <QDateTime>
#include <QLocale>
#include <QTimer>
#include "mirall/progressdispatcher.h"
#include "mirall/syncfileitem.h"
#include "ui_itemprogressdialog.h"
#include "ui_fileitemdialog.h"
namespace Mirall {
class Theme;
class SyncResult;
namespace Ui {
class ItemProgressDialog;
}
class Application;
class ItemProgressDialog : public QDialog
class FileItemDialog : public QDialog, public Ui::_fileItemDialog
{
Q_OBJECT
public:
explicit ItemProgressDialog(Application *app, QWidget *parent = 0);
~ItemProgressDialog();
void setupList();
void setSyncResult( const SyncResult& result );
explicit FileItemDialog(Theme*, QWidget *parent = 0);
void setSyncResult( const SyncResult& );
signals:
public slots:
void accept();
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
void slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem );
protected slots:
void slotSetFolderMessage();
void copyToClipboard();
signals:
void guiLog(const QString&, const QString&);
private:
void setSyncResultStatus(const SyncResult& result );
void cleanErrors( const QString& folder );
QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat) const;
void setSyncFileItems( const SyncFileItemVector& list );
void formatHeaderItem( QTreeWidgetItem *, const QList<QTreeWidgetItem*>& );
const int ErrorIndicatorRole;
Ui::ItemProgressDialog *_ui;
int _problemCounter;
QTreeWidgetItem *_newFileItem;
QTreeWidgetItem *_syncedFileItem;
QTreeWidgetItem *_deletedFileItem;
QTreeWidgetItem *_renamedFileItem;
QTreeWidgetItem *_errorFileItem;
QTreeWidgetItem *_conflictFileItem;
QTreeWidgetItem *_ignoredFileItem;
Theme *_theme;
QString _folderMessage;
QDateTime _lastSyncTime;
QTimer _timer;
};
}
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::ItemProgressDialog</class>
<widget class="QWidget" name="Mirall::ItemProgressDialog">
<class>_fileItemDialog</class>
<widget class="QWidget" name="_fileItemDialog">
<property name="geometry">
<rect>
<x>0</x>
@@ -43,7 +43,7 @@
<bool>true</bool>
</property>
<property name="columnCount">
<number>4</number>
<number>2</number>
</property>
<column>
<property name="text">
@@ -55,16 +55,13 @@
<string notr="true">2</string>
</property>
</column>
<column>
<property name="text">
<string>3</string>
</property>
</column>
<column>
<property name="text">
<string>4</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="_timelabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
+1 -1
Ver Arquivo
@@ -25,7 +25,7 @@ class FileUtils
public:
enum SubFolderListOption {
SubFolderNoOptions = 0x0,
SubFolderRecursive = 0x1
SubFolderRecursive = 0x1,
};
Q_DECLARE_FLAGS(SubFolderListOptions, SubFolderListOption)
+128 -481
Ver Arquivo
@@ -1,7 +1,5 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,108 +17,66 @@
#include "mirall/folderwatcher.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/syncresult.h"
#include "mirall/logger.h"
#include "mirall/owncloudinfo.h"
#include "mirall/utility.h"
#include "folderman.h"
#include "creds/abstractcredentials.h"
#include <QDebug>
#include <QTimer>
#include <QUrl>
#include <QFileSystemWatcher>
#include <QDir>
#include <QMessageBox>
#include <QPushButton>
namespace Mirall {
void csyncLogCatcher(int /*verbosity*/,
const char */*function*/,
const char *buffer,
void */*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent)
: QObject(parent)
, _path(path)
, _secondPath(secondPath)
, _alias(alias)
, _enabled(true)
, _thread(0)
, _csync(0)
, _csyncError(false)
, _csyncUnavail(false)
, _csync_ctx(0)
: QObject(parent),
_errorCount(0),
_path(path),
_secondPath(secondPath),
_pollTimer(new QTimer(this)),
_alias(alias),
_onlyOnlineEnabled(false),
_onlyThisLANEnabled(false),
_online(false),
_enabled(true)
{
qsrand(QTime::currentTime().msec());
_timeSinceLastSync.start();
MirallConfigFile cfgFile;
_watcher = new FolderWatcher(path, this);
_pollTimer->setSingleShot(true);
int polltime = cfgFile.remotePollInterval()- 2000 + (int)( 4000.0*qrand()/(RAND_MAX+1.0));
qDebug() << "setting remote poll timer interval to" << polltime << "msec for folder " << alias;
_pollTimer->setInterval( polltime );
QObject::connect(_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
_pollTimer->start();
_watcher = new Mirall::FolderWatcher(path, this);
MirallConfigFile cfg;
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::SystemScope) );
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::UserScope) );
_watcher->setIgnoreListFile( cfg.excludeFile() );
QObject::connect(_watcher, SIGNAL(folderChanged(const QStringList &)),
SLOT(slotChanged(const QStringList &)));
QObject::connect(this, SIGNAL(syncStarted()),
SLOT(slotSyncStarted()));
QObject::connect(this, SIGNAL(syncFinished(const SyncResult &)),
SLOT(slotSyncFinished(const SyncResult &)));
#if QT_VERSION >= 0x040700
_online = _networkMgr.isOnline();
QObject::connect(&_networkMgr, SIGNAL(onlineStateChanged(bool)), SLOT(slotOnlineChanged(bool)));
#else
_online = true;
#endif
_syncResult.setStatus( SyncResult::NotYetStarted );
// check if the local path exists
checkLocalPath();
int polltime = cfg.remotePollInterval();
qDebug() << "setting remote poll timer interval to" << polltime << "msec";
_pollTimer.setInterval( polltime );
QObject::connect(&_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
_pollTimer.start();
_syncResult.setFolder(alias);
}
bool Folder::init()
{
QString url = Utility::toCSyncScheme(ownCloudInfo::instance()->webdavUrl() + secondPath());
QString localpath = path();
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
qDebug() << "Unable to create csync-context!";
slotCSyncError(tr("Unable to create csync-context"));
_csync_ctx = 0;
} else {
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( 11 );
MirallConfigFile cfgFile;
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
csync_enable_conflictcopys(_csync_ctx);
setIgnoredFiles();
cfgFile.getCredentials()->syncContextPreInit(_csync_ctx);
if( csync_init( _csync_ctx ) < 0 ) {
qDebug() << "Could not initialize csync!" << csync_get_status(_csync_ctx) << csync_get_status_string(_csync_ctx);
slotCSyncError(CSyncThread::csyncErrorToString((CSYNC_STATUS) csync_get_status(_csync_ctx),
csync_get_status_string(_csync_ctx)));
csync_destroy(_csync_ctx);
_csync_ctx = 0;
}
}
return _csync_ctx;
}
Folder::~Folder()
{
if( _thread ) {
_thread->quit();
csync_request_abort(_csync_ctx);
_thread->wait();
}
delete _csync;
// Destroy csync here.
csync_destroy(_csync_ctx);
}
void Folder::checkLocalPath()
@@ -173,11 +129,6 @@ QString Folder::path() const
return p;
}
bool Folder::isBusy() const
{
return ( _thread && _thread->isRunning() );
}
QString Folder::secondPath() const
{
return _secondPath;
@@ -197,6 +148,9 @@ void Folder::setSyncEnabled( bool doit )
{
_enabled = doit;
_watcher->setEventsEnabled( doit );
if( doit && ! _pollTimer->isActive() ) {
_pollTimer->start();
}
qDebug() << "setSyncEnabled - ############################ " << doit;
if( doit ) {
@@ -209,22 +163,85 @@ void Folder::setSyncEnabled( bool doit )
}
}
bool Folder::onlyOnlineEnabled() const
{
return _onlyOnlineEnabled;
}
void Folder::setOnlyOnlineEnabled(bool enabled)
{
_onlyOnlineEnabled = enabled;
}
bool Folder::onlyThisLANEnabled() const
{
return _onlyThisLANEnabled;
}
void Folder::setOnlyThisLANEnabled(bool enabled)
{
_onlyThisLANEnabled = enabled;
}
int Folder::pollInterval() const
{
return _pollTimer->interval();
}
void Folder::setSyncState(SyncResult::Status state)
{
_syncResult.setStatus(state);
}
void Folder::setPollInterval(int milliseconds)
{
_pollTimer->setInterval( milliseconds );
}
int Folder::errorCount()
{
return _errorCount;
}
void Folder::resetErrorCount()
{
_errorCount = 0;
}
void Folder::incrementErrorCount()
{
// if the error count gets higher than three, the interval timer
// of the watcher is doubled.
_errorCount++;
if( _errorCount > 1 ) {
int interval = _watcher->eventInterval();
int newInt = 2*interval;
qDebug() << "Set new watcher interval to " << newInt;
_watcher->setEventInterval( newInt );
_errorCount = 0;
}
}
SyncResult Folder::syncResult() const
{
return _syncResult;
}
void Folder::evaluateSync(const QStringList &/*pathList*/)
void Folder::evaluateSync(const QStringList &pathList)
{
if( !_enabled ) {
qDebug() << "*" << alias() << "sync skipped, disabled!";
return;
}
if (!_online && onlyOnlineEnabled()) {
qDebug() << "*" << alias() << "sync skipped, not online";
return;
}
// stop the poll timer here. Its started again in the slot of
// sync finished.
qDebug() << "* " << alias() << "Poll timer disabled";
_pollTimer->stop();
_syncResult.setStatus( SyncResult::NotYetStarted );
emit scheduleToSync( alias() );
@@ -233,36 +250,15 @@ void Folder::evaluateSync(const QStringList &/*pathList*/)
void Folder::slotPollTimerTimeout()
{
qDebug() << "* Polling" << alias() << "for changes. (time since next sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval()) {
qDebug() << "* Force Sync now";
evaluateSync(QStringList());
} else {
RequestEtagJob* job = new RequestEtagJob(secondPath(), this);
// check if the etag is different
QObject::connect(job, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
QObject::connect(job, SIGNAL(networkError()), this, SLOT(slotNetworkUnavailable()));
}
qDebug() << "* Polling" << alias() << "for changes. Ignoring all pending events until now";
_watcher->clearPendingEvents();
evaluateSync(QStringList());
}
void Folder::etagRetreived(const QString& etag)
void Folder::slotOnlineChanged(bool online)
{
qDebug() << "* Compare etag with previous etag: " << (_lastEtag != etag);
// re-enable sync if it was disabled because network was down
FolderMan::instance()->setSyncEnabled(true);
if (_lastEtag != etag) {
_lastEtag = etag;
evaluateSync(QStringList());
}
}
void Folder::slotNetworkUnavailable()
{
_syncResult.setStatus(SyncResult::Unavailable);
emit syncStateChange();
qDebug() << "* " << alias() << "is" << (online ? "now online" : "no longer online");
_online = online;
}
void Folder::slotChanged(const QStringList &pathList)
@@ -271,102 +267,36 @@ void Folder::slotChanged(const QStringList &pathList)
evaluateSync(pathList);
}
void Folder::bubbleUpSyncResult()
void Folder::slotSyncStarted()
{
// count new, removed and updated items
int newItems = 0;
int removedItems = 0;
int updatedItems = 0;
int ignoredItems = 0;
// disable events until syncing is done
_watcher->setEventsEnabled(false);
}
SyncFileItem firstItemNew;
SyncFileItem firstItemDeleted;
SyncFileItem firstItemUpdated;
void Folder::slotSyncFinished(const SyncResult &result)
{
_watcher->setEventsEnabledDelayed(2000);
Logger *logger = Logger::instance();
qDebug() << "OO folder slotSyncFinished: result: " << int(result.status());
emit syncStateChange();
foreach (const SyncFileItem &item, _syncResult.syncFileItemVector() ) {
if( item._instruction == CSYNC_INSTRUCTION_ERROR ) {
slotCSyncError( tr("File %1: %2").arg(item._file).arg(item._errorString) );
logger->postGuiLog(tr("File %1").arg(item._file), item._errorString);
} else {
if (item._dir == SyncFileItem::Down) {
switch (item._instruction) {
case CSYNC_INSTRUCTION_NEW:
newItems++;
if (firstItemNew.isEmpty())
firstItemNew = item;
break;
case CSYNC_INSTRUCTION_REMOVE:
removedItems++;
if (firstItemDeleted.isEmpty())
firstItemDeleted = item;
break;
case CSYNC_INSTRUCTION_UPDATED:
updatedItems++;
if (firstItemUpdated.isEmpty())
firstItemUpdated = item;
break;
case CSYNC_INSTRUCTION_ERROR:
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
break;
default:
// nothing.
break;
}
} else if( item._dir == SyncFileItem::None ) { // ignored files counting.
if( item._instruction == CSYNC_INSTRUCTION_IGNORE ) {
ignoredItems++;
}
}
}
}
_syncResult.setWarnCount(ignoredItems);
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
if (newItems > 0) {
QString file = QDir::toNativeSeparators(firstItemNew._file);
if (newItems == 1)
logger->postGuiLog(tr("New file available"), tr("'%1' has been synced to this machine.").arg(file));
else
logger->postGuiLog(tr("New files available"), tr("'%1' and %n other file(s) have been synced to this machine.",
"", newItems-1).arg(file));
}
if (removedItems > 0) {
QString file = QDir::toNativeSeparators(firstItemDeleted._file);
if (removedItems == 1)
logger->postGuiLog(tr("File removed"), tr("'%1' has been removed.").arg(file));
else
logger->postGuiLog(tr("Files removed"), tr("'%1' and %n other file(s) have been removed.",
"", removedItems-1).arg(file));
}
if (updatedItems > 0) {
QString file = QDir::toNativeSeparators(firstItemUpdated._file);
if (updatedItems == 1)
logger->postGuiLog(tr("File updated"), tr("'%1' has been updated.").arg(file));
else
logger->postGuiLog(tr("Files updated"), tr("'%1' and %n other file(s) have been updated.",
"", updatedItems-1).arg(file));
// reenable the poll timer if folder is sync enabled
if( syncEnabled() ) {
qDebug() << "* " << alias() << "Poll timer enabled with " << _pollTimer->interval() << "milliseconds";
_pollTimer->start();
} else {
qDebug() << "* Not enabling poll timer for " << alias();
_pollTimer->stop();
}
}
void Folder::slotLocalPathChanged( const QString& dir )
{
QDir notifiedDir(dir);
QDir localPath( path() );
QDir localPath(_path );
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
if( notifiedDir == localPath ) {
if( !localPath.exists() ) {
qDebug() << "XXXXXXX The sync folder root was removed!!";
if( _thread && _thread->isRunning() ) {
qDebug() << "CSync currently running, set wipe flag!!";
} else {
qDebug() << "CSync not running, wipe it now!!";
wipe();
}
qDebug() << "ALARM: The local path was DELETED!";
}
}
@@ -382,303 +312,20 @@ QString Folder::configFile()
return _configFile;
}
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
void Folder::setBackend( const QString& b )
{
_syncResult.setSyncFileItemVector(items);
_backend = b;
}
void Folder::slotCatchWatcherError(const QString& error)
QString Folder::backend() const
{
Logger::instance()->postGuiLog(tr("Error"), error);
return _backend;
}
void Folder::slotTerminateSync()
{
qDebug() << "folder " << alias() << " Terminating!";
MirallConfigFile cfg;
QString configDir = cfg.configPath();
qDebug() << "csync's Config Dir: " << configDir;
if( _thread && _csync ) {
csync_request_abort(_csync_ctx);
_thread->quit();
_thread->wait();
_csync->deleteLater();
delete _thread;
_csync = 0;
_thread = 0;
csync_resume(_csync_ctx);
}
if( ! configDir.isEmpty() ) {
QFile file( configDir + QLatin1String("/lock"));
if( file.exists() ) {
qDebug() << "After termination, lock file exists and gets removed.";
file.remove();
}
}
_errors.append( tr("The CSync thread terminated.") );
_csyncError = true;
qDebug() << "-> CSync Terminated!";
slotCSyncFinished();
}
// This removes the csync File database if the sync folder definition is removed
// permanentely. This is needed to provide a clean startup again in case another
// local folder is synced to the same ownCloud.
// See http://bugs.owncloud.org/thebuggenie/owncloud/issues/oc-788
void Folder::wipe()
{
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
QFile file(stateDbFile);
if( file.exists() ) {
if( !file.remove()) {
qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile;
} else {
qDebug() << "wipe: Removed csync StateDB " << stateDbFile;
}
} else {
qDebug() << "WRN: statedb is empty, can not remove.";
}
// Check if the tmp database file also exists
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
QFile ctmpFile( ctmpName );
if( ctmpFile.exists() ) {
ctmpFile.remove();
}
}
void Folder::setIgnoredFiles()
{
MirallConfigFile cfgFile;
csync_clear_exclude_list( _csync_ctx );
QString excludeList = cfgFile.excludeFile( MirallConfigFile::SystemScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added system ignore list to csync:" << excludeList.toUtf8();
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
}
excludeList = cfgFile.excludeFile( MirallConfigFile::UserScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added user defined ignore list to csync:" << excludeList.toUtf8();
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
}
}
void Folder::setProxy()
{
if( _csync_ctx ) {
/* Store proxy */
QUrl proxyUrl(ownCloudInfo::instance()->webdavUrl());
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(proxyUrl);
// We set at least one in Application
Q_ASSERT(proxies.count() > 0);
QNetworkProxy proxy = proxies.first();
if (proxy.type() == QNetworkProxy::NoProxy) {
qDebug() << "Passing NO proxy to csync for" << proxyUrl;
} else {
qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type()
<< " to csync for" << proxyUrl;
}
int proxyPort = proxy.port();
csync_set_module_property(_csync_ctx, "proxy_type", (char*) proxyTypeToCStr(proxy.type()) );
csync_set_module_property(_csync_ctx, "proxy_host", proxy.hostName().toUtf8().data() );
csync_set_module_property(_csync_ctx, "proxy_port", &proxyPort );
csync_set_module_property(_csync_ctx, "proxy_user", proxy.user().toUtf8().data() );
csync_set_module_property(_csync_ctx, "proxy_pwd" , proxy.password().toUtf8().data() );
}
}
const char* Folder::proxyTypeToCStr(QNetworkProxy::ProxyType type)
{
switch (type) {
case QNetworkProxy::NoProxy:
return "NoProxy";
case QNetworkProxy::DefaultProxy:
return "DefaultProxy";
case QNetworkProxy::Socks5Proxy:
return "Socks5Proxy";
case QNetworkProxy::HttpProxy:
return "HttpProxy";
case QNetworkProxy::HttpCachingProxy:
return "HttpCachingProxy";
case QNetworkProxy::FtpCachingProxy:
return "FtpCachingProxy";
default:
return "NoProxy";
}
}
void Folder::startSync(const QStringList &pathList)
{
Q_UNUSED(pathList)
if (!_csync_ctx) {
// no _csync_ctx yet, initialize it.
init();
setProxy();
if (!_csync_ctx) {
qDebug() << Q_FUNC_INFO << "init failed.";
// the error should already be set
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
return;
}
}
if (_thread && _thread->isRunning()) {
qCritical() << "* ERROR csync is still running and new sync requested.";
return;
}
if (_thread)
_thread->quit();
delete _csync;
delete _thread;
_errors.clear();
_csyncError = false;
_csyncUnavail = false;
_syncResult.clearErrors();
_syncResult.setStatus( SyncResult::SyncPrepare );
emit syncStateChange();
qDebug() << "*** Start syncing";
_thread = new QThread(this);
_thread->setPriority(QThread::LowPriority);
setIgnoredFiles();
_csync = new CSyncThread( _csync_ctx );
_csync->moveToThread(_thread);
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
connect(_csync, SIGNAL(started()), SLOT(slotCSyncStarted()), Qt::QueuedConnection);
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
//blocking connection so the message box happens in this thread, but block the csync thread.
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
connect(_csync, SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
_thread->start();
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
// disable events until syncing is done
_watcher->setEventsEnabled(false);
_pollTimer.stop();
emit syncStarted();
}
void Folder::slotCSyncError(const QString& err)
{
_errors.append( err );
_csyncError = true;
}
void Folder::slotCSyncStarted()
{
qDebug() << " * csync thread started";
_syncResult.setStatus(SyncResult::SyncRunning);
emit syncStateChange();
}
void Folder::slotCsyncUnavailable()
{
_csyncUnavail = true;
}
void Folder::slotCSyncFinished()
{
qDebug() << "-> CSync Finished slot with error " << _csyncError;
_watcher->setEventsEnabledDelayed(2000);
_pollTimer.start();
_timeSinceLastSync.restart();
bubbleUpSyncResult();
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
qDebug() << " ** error Strings: " << _errors;
_syncResult.setErrorStrings( _errors );
qDebug() << " * owncloud csync thread finished with error";
} else if (_csyncUnavail) {
_syncResult.setStatus(SyncResult::Unavailable);
} else if( _syncResult.warnCount() > 0 ) {
// there have been warnings on the way.
_syncResult.setStatus(SyncResult::Problem);
} else {
_syncResult.setStatus(SyncResult::Success);
}
if( _thread && _thread->isRunning() ) {
_thread->quit();
}
emit syncStateChange();
ownCloudInfo::instance()->getQuotaRequest("/");
emit syncFinished( _syncResult );
}
void Folder::slotTransmissionProgress(const Progress::Info& progress)
{
Progress::Info newInfo = progress;
newInfo.folder = alias();
if(newInfo.current_file.startsWith(QLatin1String("ownclouds://")) ||
newInfo.current_file.startsWith(QLatin1String("owncloud://")) ) {
// rip off the whole ownCloud URL.
QString remotePathUrl = ownCloudInfo::instance()->webdavUrl() + secondPath();
newInfo.current_file.remove(Utility::toCSyncScheme(remotePathUrl));
}
QString localPath = path();
if( newInfo.current_file.startsWith(localPath) ) {
// remove the local dir.
newInfo.current_file = newInfo.current_file.right( newInfo.current_file.length() - localPath.length());
}
// remember problems happening to set the correct Sync status in slot slotCSyncFinished.
if( newInfo.kind == Progress::StartSync ) {
_syncResult.setWarnCount(0);
}
if( newInfo.kind == Progress::Error ) {
_syncResult.setWarnCount( _syncResult.warnCount()+1 );
}
ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo);
}
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{
QString msg = direction == SyncFileItem::Down ?
tr("This sync would remove all the files in the local sync folder '%1'.\n"
"If you or your administrator have reset your account on the server, choose "
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
tr("This sync would remove all the files in the sync folder '%1'.\n"
"This might be because the folder was silently reconfigured, or that all "
"the file were manually removed.\n"
"Are you sure you want to perform this operation?");
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
msg.arg(alias()));
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;
}
*cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) {
wipe();
}
}
} // namespace Mirall
+111 -88
Ver Arquivo
@@ -1,7 +1,5 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,61 +15,38 @@
#ifndef MIRALL_FOLDER_H
#define MIRALL_FOLDER_H
#include "mirall/syncresult.h"
#include "mirall/progressdispatcher.h"
#include "mirall/csyncthread.h"
#include <QDir>
#include <QHash>
#include <QNetworkAccessManager>
#include <QNetworkProxy>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QDebug>
#include <QHash>
#include <QTimer>
#include <qelapsedtimer.h>
#if QT_VERSION >= 0x040700
#include <QNetworkConfigurationManager>
#endif
#include "mirall/syncresult.h"
class QAction;
class QIcon;
class QFileSystemWatcher;
class QThread;
namespace Mirall {
class FolderWatcher;
typedef enum SyncFileStatus_s {
STATUS_NONE,
STATUS_EVAL,
STATUS_REMOVE,
STATUS_RENAME,
STATUS_NEW,
STATUS_CONFLICT,
STATUS_IGNORE,
STATUS_SYNC,
STATUS_STAT_ERROR,
STATUS_ERROR,
STATUS_UPDATED
} SyncFileStatus;
class Folder : public QObject
{
Q_OBJECT
protected:
friend class FolderMan;
Folder(const QString&, const QString&, const QString& , QObject*parent = 0L);
public:
~Folder();
Folder(const QString&, const QString&, const QString& , QObject*parent = 0L);
virtual ~Folder();
typedef QHash<QString, Folder*> Map;
typedef QHashIterator<QString, Folder*> MapIterator;
/**
* Get status about a single file.
*/
SyncFileStatus fileStatus( const QString& );
/**
* alias or nickname
*/
@@ -81,16 +56,12 @@ public:
* local folder path
*/
QString path() const;
/**
* remote folder path
*/
QString secondPath() const;
virtual QString secondPath() const;
/**
* local folder path with native separators
*/
QString nativePath() const;
/**
* switch sync on or off
* If the sync is switched off, the startSync method is not going to
@@ -100,17 +71,69 @@ public:
bool syncEnabled() const;
/**
* Starts a sync operation
*
* If the list of changed files is known, it is passed.
*
* If the list of changed files is empty, the folder
* implementation should figure it by itself of
* perform a full scan of changes
*/
virtual void startSync(const QStringList &pathList) = 0;
/**
* True if the folder is busy and can't initiate
* a synchronization
*/
virtual bool isBusy() const;
virtual bool isBusy() const = 0;
/**
* only sync when online in the network
*/
bool onlyOnlineEnabled() const;
/**
* @see onlyOnlineEnabled
*/
void setOnlyOnlineEnabled(bool enabled);
/**
* only sync when online in the same LAN
* as the one used during setup
*/
bool onlyThisLANEnabled() const;
/**
* @see onlyThisLANEnabled
*/
void setOnlyThisLANEnabled(bool enabled);
/**
* error counter, stop syncing after the counter reaches a certain
* number.
*/
int errorCount();
void resetErrorCount();
void incrementErrorCount();
/**
* return the last sync result with error message and status
*/
SyncResult syncResult() const;
/**
* set the backend description string.
*/
void setBackend( const QString& );
/**
* get the backend description string.
*/
QString backend() const;
/**
* set the config file name.
*/
@@ -122,6 +145,9 @@ public:
*/
virtual void wipe();
QIcon icon( int size ) const;
QTimer *_pollTimer;
signals:
void syncStateChange();
void syncStarted();
@@ -129,6 +155,7 @@ signals:
void scheduleToSync( const QString& );
public slots:
void slotSyncFinished(const SyncResult &);
/**
*
@@ -138,47 +165,48 @@ public slots:
/**
* terminate the current sync run
*/
void slotTerminateSync();
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
virtual void slotTerminateSync() = 0;
/**
* Starts a sync operation
*
* If the list of changed files is known, it is passed.
* Sets minimum amounts of milliseconds that will separate
* poll intervals
*/
void startSync(const QStringList &pathList = QStringList());
void setPollInterval( int );
private slots:
void slotCSyncStarted();
void slotCSyncError(const QString& );
void slotCsyncUnavailable();
void slotCSyncFinished();
/**
* If folder is network-based, reimplement to react to proxy changes
*/
virtual void setProxy() {}
void slotTransmissionProgress(const Progress::Info& progress);
protected:
/**
* The minimum amounts of seconds to wait before
* doing a full sync to see if the remote changed
*/
int pollInterval() const;
void setSyncState(SyncResult::Status state);
FolderWatcher *_watcher;
int _errorCount;
SyncResult _syncResult;
protected slots:
void slotOnlineChanged(bool online);
void slotPollTimerTimeout();
void etagRetreived(const QString &);
void slotNetworkUnavailable();
/* called when the watcher detect a list of changed
paths */
void slotSyncStarted();
/**
* Triggered by a file system watcher on the local sync dir
*/
void slotLocalPathChanged( const QString& );
void slotThreadTreeWalkResult(const SyncFileItemVector& );
void slotCatchWatcherError( const QString& );
virtual void slotLocalPathChanged( const QString& );
protected:
bool init();
void setSyncState(SyncResult::Status state);
void setIgnoredFiles();
void setProxy();
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
void bubbleUpSyncResult();
private:
/**
* Starts a sync (calling startSync)
@@ -186,28 +214,23 @@ protected:
*/
void evaluateSync(const QStringList &pathList);
void checkLocalPath();
virtual void checkLocalPath();
QString _path;
QString _secondPath;
QString _alias;
bool _onlyOnlineEnabled;
bool _onlyThisLANEnabled;
QString _configFile;
QFileSystemWatcher *_pathWatcher;
bool _enabled;
FolderWatcher *_watcher;
SyncResult _syncResult;
QThread *_thread;
CSyncThread *_csync;
QStringList _errors;
bool _csyncError;
bool _csyncUnavail;
bool _wipeDb;
Progress::Kind _progressKind;
QTimer _pollTimer;
QString _lastEtag;
QElapsedTimer _timeSinceLastSync;
CSYNC *_csync_ctx;
QFileSystemWatcher *_pathWatcher;
#if QT_VERSION >= 0x040700
QNetworkConfigurationManager _networkMgr;
#endif
bool _online;
bool _enabled;
QString _backend;
};
+83 -140
Ver Arquivo
@@ -14,11 +14,10 @@
#include "mirall/folderman.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/folder.h"
#include "mirall/owncloudfolder.h"
#include "mirall/syncresult.h"
#include "mirall/inotify.h"
#include "mirall/theme.h"
#include "owncloudinfo.h"
#ifdef Q_OS_MAC
#include <CoreServices/CoreServices.h>
@@ -33,8 +32,6 @@
namespace Mirall {
FolderMan* FolderMan::_instance = 0;
FolderMan::FolderMan(QObject *parent) :
QObject(parent),
_syncEnabled( true )
@@ -51,17 +48,11 @@ FolderMan::FolderMan(QObject *parent) :
this, SIGNAL(folderSyncStateChange(const QString &)));
}
FolderMan *FolderMan::instance()
{
if(!_instance)
_instance = new FolderMan;
return _instance;
}
FolderMan::~FolderMan()
{
qDeleteAll(_folderMap);
foreach (Folder *folder, _folderMap) {
delete folder;
}
}
Mirall::Folder::Map FolderMan::map()
@@ -73,7 +64,15 @@ Mirall::Folder::Map FolderMan::map()
int FolderMan::setupFolders()
{
// setup a handler to look for configuration changes
return setupKnownFolders();
#ifdef CHECK_FOR_SETUP_CHANGES
_configFolderWatcher = new FolderWatcher( _folderConfigPath );
_configFolderWatcher->setEventInterval(20000);
connect(_configFolderWatcher, SIGNAL(folderChanged(const QStringList &)),
this, SLOT( slotReparseConfiguration()) );
#endif
int cnt = setupKnownFolders();
return cnt;
}
void FolderMan::slotReparseConfiguration()
@@ -83,6 +82,9 @@ void FolderMan::slotReparseConfiguration()
int FolderMan::unloadAllFolders()
{
// first terminate sync jobs.
terminateCurrentSync();
int cnt = 0;
// clear the list of existing folders.
@@ -244,28 +246,43 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
// QString connection = settings.value( QLatin1String("connection") ).toString();
QString alias = unescapeAlias( escapedAlias );
if (backend.isEmpty() || backend != QLatin1String("owncloud")) {
qWarning() << "obsolete configuration of type" << backend;
return 0;
if (!backend.isEmpty()) {
if( backend == QLatin1String("owncloud") ) {
MirallConfigFile cfgFile;
// assemble the owncloud url to pass to csync, incl. webdav
QString oCUrl = cfgFile.ownCloudUrl( QString::null, true );
// cut off the leading slash, oCUrl always has a trailing.
if( targetPath.startsWith(QLatin1Char('/')) ) {
targetPath.remove(0,1);
}
folder = new ownCloudFolder( alias, path, oCUrl + targetPath, this );
folder->setConfigFile(file);
} else {
qWarning() << "unknown backend" << backend;
return 0;
}
}
// cut off the leading slash, oCUrl always has a trailing.
if( targetPath.startsWith(QLatin1Char('/')) ) {
targetPath.remove(0,1);
if( folder ) {
folder->setBackend( backend );
// folder->setOnlyOnlineEnabled(settings.value("folder/onlyOnline", false).toBool());
folder->setOnlyThisLANEnabled(settings.value(QLatin1String("folder/onlyThisLAN"), false).toBool());
_folderMap[alias] = folder;
qDebug() << "Adding folder to Folder Map " << folder;
/* Use a signal mapper to connect the signals to the alias */
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted()));
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
}
folder = new Folder( alias, path, targetPath, this );
folder->setConfigFile(file);
qDebug() << "Adding folder to Folder Map " << folder;
_folderMap[alias] = folder;
/* Use a signal mapper to connect the signals to the alias */
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted()));
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
return folder;
}
@@ -296,7 +313,7 @@ void FolderMan::terminateSyncProcess( const QString& alias )
f->slotTerminateSync();
if(_currentSyncFolder == folderAlias )
_currentSyncFolder.clear();
_currentSyncFolder = QString::null;
}
}
}
@@ -313,21 +330,19 @@ Folder *FolderMan::folder( const QString& alias )
SyncResult FolderMan::syncResult( const QString& alias )
{
SyncResult res;
Folder *f = folder( alias );
return syncResult(f);
}
SyncResult FolderMan::syncResult( Folder *f )
{
return f ? f->syncResult() : SyncResult();
if( f ) {
res = f->syncResult();
}
return res;
}
void FolderMan::slotScheduleAllFolders()
{
foreach( Folder *f, _folderMap.values() ) {
if (f->syncEnabled()) {
slotScheduleSync( f->alias() );
}
slotScheduleSync( f->alias() );
}
}
@@ -346,19 +361,17 @@ void FolderMan::slotScheduleSync( const QString& alias )
}
if( ! _scheduleQueue.contains(alias )) {
_scheduleQueue.enqueue(alias);
_scheduleQueue.append(alias);
} else {
qDebug() << " II> Sync for folder " << alias << " already scheduled, do not enqueue!";
}
slotScheduleFolderSync();
}
void FolderMan::setSyncEnabled( bool enabled )
{
if (!_syncEnabled && enabled && !_scheduleQueue.isEmpty()) {
// We have things in our queue that were waiting the the connection to go back on.
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
}
_syncEnabled = enabled;
}
@@ -381,14 +394,11 @@ void FolderMan::slotScheduleFolderSync()
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
if( ! _scheduleQueue.isEmpty() ) {
const QString alias = _scheduleQueue.dequeue();
const QString alias = _scheduleQueue.takeFirst();
if( _folderMap.contains( alias ) ) {
ownCloudInfo::instance()->getQuotaRequest("/");
Folder *f = _folderMap[alias];
_currentSyncFolder = alias;
if (f->syncEnabled()) {
f->startSync( QStringList() );
}
f->startSync( QStringList() );
}
}
}
@@ -410,17 +420,28 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
}
void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder, const QString& targetPath )
/**
* Add a folder definition to the config
* Params:
* QString backend
* QString alias
* QString sourceFolder on local machine
* QString targetPath on remote
* bool onlyThisLAN, currently unused.
*/
void FolderMan::addFolderDefinition( const QString& backend, const QString& alias,
const QString& sourceFolder, const QString& targetPath,
bool onlyThisLAN )
{
QString escapedAlias = escapeAlias(alias);
// Create a settings file named after the alias
QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat);
settings.beginGroup(escapedAlias);
settings.setValue(QLatin1String("localPath"), sourceFolder );
settings.setValue(QLatin1String("targetPath"), targetPath );
// for compat reasons
settings.setValue(QLatin1String("backend"), "owncloud" );
settings.setValue(QLatin1String("connection"), Theme::instance()->appName());
settings.setValue(QString::fromLatin1("%1/localPath").arg(escapedAlias), sourceFolder );
settings.setValue(QString::fromLatin1("%1/targetPath").arg(escapedAlias), targetPath );
settings.setValue(QString::fromLatin1("%1/backend").arg(escapedAlias), backend );
settings.setValue(QString::fromLatin1("%1/connection").arg(escapedAlias), Theme::instance()->appName());
settings.setValue(QString::fromLatin1("%1/onlyThisLAN").arg(escapedAlias), onlyThisLAN );
settings.sync();
}
@@ -512,89 +533,11 @@ bool FolderMan::startFromScratch( const QString& localFolder )
return false;
}
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
void FolderMan::setProxy()
{
SyncResult overallResult(SyncResult::Undefined);
foreach ( Folder *folder, folders ) {
SyncResult folderResult = folder->syncResult();
SyncResult::Status syncStatus = folderResult.status();
switch( syncStatus ) {
case SyncResult::Undefined:
if ( overallResult.status() != SyncResult::Error )
overallResult.setStatus(SyncResult::Error);
break;
case SyncResult::NotYetStarted:
overallResult.setStatus( SyncResult::NotYetStarted );
break;
case SyncResult::SyncPrepare:
overallResult.setStatus( SyncResult::SyncPrepare );
break;
case SyncResult::SyncRunning:
overallResult.setStatus( SyncResult::SyncRunning );
break;
case SyncResult::Unavailable:
overallResult.setStatus( SyncResult::Unavailable );
break;
case SyncResult::Success:
if( overallResult.status() == SyncResult::Undefined )
overallResult.setStatus( SyncResult::Success );
break;
case SyncResult::Error:
overallResult.setStatus( SyncResult::Error );
break;
case SyncResult::SetupError:
if ( overallResult.status() != SyncResult::Error )
overallResult.setStatus( SyncResult::SetupError );
break;
case SyncResult::Problem:
if ( overallResult.status() != SyncResult::Problem )
overallResult.setStatus( SyncResult::Problem );
break;
// no default case on purpose, check compiler warnings
}
foreach( Folder *f, _folderMap.values() ) {
f->setProxy();
}
return overallResult;
}
QString FolderMan::statusToString( SyncResult syncStatus, bool enabled ) const
{
QString folderMessage;
switch( syncStatus.status() ) {
case SyncResult::Undefined:
folderMessage = tr( "Undefined State." );
break;
case SyncResult::NotYetStarted:
folderMessage = tr( "Waits to start syncing." );
break;
case SyncResult::SyncPrepare:
folderMessage = tr( "Preparing for sync." );
break;
case SyncResult::SyncRunning:
folderMessage = tr( "Sync is running." );
break;
case SyncResult::Unavailable:
folderMessage = tr( "Server is currently not available." );
break;
case SyncResult::Success:
folderMessage = tr( "Last Sync was successful." );
break;
case SyncResult::Error:
break;
case SyncResult::Problem:
folderMessage = tr( "Last Sync was successful, but with warnings on individual files.");
break;
case SyncResult::SetupError:
folderMessage = tr( "Setup Error." );
break;
// no default case on purpose, check compiler warnings
}
if( !enabled ) {
// sync is disabled.
folderMessage = tr( "%1 (Sync is paused)" ).arg(folderMessage);
}
return folderMessage;
}
} // namespace Mirall
+32 -24
Ver Arquivo
@@ -18,7 +18,6 @@
#include <QObject>
#include <QQueue>
#include <QList>
#include "mirall/folder.h"
#include "mirall/folderwatcher.h"
@@ -26,15 +25,15 @@
class QSignalMapper;
class SyncResult;
namespace Mirall {
class SyncResult;
class FolderMan : public QObject
{
Q_OBJECT
public:
static FolderMan* instance();
explicit FolderMan(QObject *parent = 0);
~FolderMan();
int setupFolders();
@@ -44,43 +43,55 @@ public:
/**
* Add a folder definition to the config
* Params:
* QString backend
* QString alias
* QString sourceFolder on local machine
* QString targetPath on remote
* bool onlyThisLAN, currently unused.
*/
void addFolderDefinition(const QString&, const QString&, const QString& );
void addFolderDefinition( const QString&, const QString&, const QString&, const QString&, bool );
/** Returns the folder by alias or NULL if no folder with the alias exists. */
/**
* return the folder by alias or NULL if no folder with the alias exists.
*/
Folder *folder( const QString& );
/** Returns the last sync result by alias */
/**
* return the last sync result by alias
*/
SyncResult syncResult( const QString& );
/** Returns the last sync result by Folder */
SyncResult syncResult( Folder* );
/** Creates a folder for a specific configuration, identified by alias. */
/**
* creates a folder for a specific configuration, identified by alias.
*/
Folder* setupFolderFromConfigFile(const QString & );
/** Wipes all folder defintions. No way back! */
/**
* wipes all folder defintions. No way back!
*/
void removeAllFolderDefinitions();
/** Removes csync journals from all folders. */
/**
* Removes csync journals from all folders.
*/
void wipeAllJournals();
/**
* Ensures that a given directory does not contain a .csync_journal.
*
* @returns false if the journal could not be removed, true otherwise.
* @returns false if the journal could not be removed, false otherwise.
*/
static bool ensureJournalGone(const QString &path);
/** Creates a new and empty local directory. */
/**
* Creates a new and empty local directory.
*/
bool startFromScratch( const QString& );
QString statusToString( SyncResult, bool enabled ) const;
static SyncResult accountStatus( const QList<Folder*> &folders );
/**
* called whenever proxy configuration changes
*/
void setProxy();
signals:
/**
@@ -130,17 +141,14 @@ private:
void removeFolder( const QString& );
FolderWatcher *_configFolderWatcher;
Folder::Map _folderMap;
QString _folderConfigPath;
QSignalMapper *_folderChangeSignalMapper;
QString _currentSyncFolder;
QStringList _scheduleQueue;
bool _syncEnabled;
QQueue<QString> _scheduleQueue;
explicit FolderMan(QObject *parent = 0);
static FolderMan *_instance;
};
} // namespace Mirall
}
#endif // FOLDERMAN_H
-306
Ver Arquivo
@@ -1,306 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "mirall/folderstatusmodel.h"
#include "mirall/utility.h"
#include <QtCore>
#include <QtGui>
namespace Mirall {
FolderStatusModel::FolderStatusModel()
:QStandardItemModel()
{
}
Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex& ) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::EditRole)
return QVariant();
else
return QStandardItemModel::data(index,role);
}
// ====================================================================================
FolderStatusDelegate::FolderStatusDelegate()
:QStyledItemDelegate()
{
}
FolderStatusDelegate::~FolderStatusDelegate()
{
// TODO Auto-generated destructor stub
}
//alocate each item size in listview.
QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem & option ,
const QModelIndex & index) const
{
Q_UNUSED(option)
QFont aliasFont = option.font;
QFont font = option.font;
aliasFont.setPointSize( font.pointSize() +2 );
QFontMetrics fm(font);
QFontMetrics aliasFm(aliasFont);
int aliasMargin = aliasFm.height()/2;
int margin = fm.height()/4;
// calc height
int h = aliasMargin; // margin to top
h += aliasFm.height(); // alias
h += margin; // between alias and local path
h += fm.height(); // local path
h += margin; // between local and remote path
h += fm.height(); // remote path
h += aliasMargin; // bottom margin
// add some space to show an error condition.
if( ! qvariant_cast<QString>(index.data(FolderErrorMsg)).isEmpty() ) {
h += aliasMargin*2+fm.height();
}
if( qvariant_cast<bool>(index.data(AddProgressSpace)) ) {
int margin = fm.height()/4;
h += (5 * margin); // All the margins
h += 2* fm.boundingRect(tr("File")).height();
}
return QSize( 0, h);
}
void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter,option,index);
painter->save();
QFont aliasFont = option.font;
QFont subFont = option.font;
QFont errorFont = subFont;
QFont progressFont = subFont;
progressFont.setPointSize( subFont.pointSize()-1);
//font.setPixelSize(font.weight()+);
aliasFont.setBold(true);
aliasFont.setPointSize( subFont.pointSize()+2 );
QFontMetrics subFm( subFont );
QFontMetrics aliasFm( aliasFont );
QFontMetrics progressFm( progressFont );
int aliasMargin = aliasFm.height()/2;
int margin = subFm.height()/4;
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole));
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole));
QString errorText = qvariant_cast<QString>(index.data(FolderErrorMsg));
int overallPercent = qvariant_cast<int>(index.data(SyncProgressOverallPercent));
QString overallString = qvariant_cast<QString>(index.data(SyncProgressOverallString));
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
int warningCount = qvariant_cast<int>(index.data(WarningCount));
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
// QString statusText = qvariant_cast<QString>(index.data(FolderStatus));
bool syncEnabled = index.data(FolderSyncEnabled).toBool();
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
QRect iconRect = option.rect;
QRect aliasRect = option.rect;
iconRect.setLeft( aliasMargin );
iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2);
// alias box
aliasRect.setTop(aliasRect.top() + aliasMargin );
aliasRect.setBottom(aliasRect.top() + aliasFm.height());
aliasRect.setRight(aliasRect.right() - aliasMargin );
// remote directory box
QRect remotePathRect = aliasRect;
remotePathRect.setTop(aliasRect.bottom() + margin );
remotePathRect.setBottom(remotePathRect.top() + subFm.height());
// local directory box
QRect localPathRect = remotePathRect;
localPathRect.setTop( remotePathRect.bottom() + margin );
localPathRect.setBottom( localPathRect.top() + subFm.height());
iconRect.setBottom(localPathRect.bottom());
iconRect.setWidth(iconRect.height());
int nextToIcon = iconRect.right()+aliasMargin;
aliasRect.setLeft(nextToIcon);
localPathRect.setLeft(nextToIcon);
remotePathRect.setLeft(nextToIcon);
int iconSize = iconRect.width();
QPixmap pm = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled );
painter->drawPixmap(QPoint(iconRect.left(), iconRect.top()), pm);
// only show the warning icon if the sync is running. Otherwise its
// encoded in the status icon.
if( warningCount > 0 && syncOngoing) {
QRect warnRect;
warnRect.setLeft(iconRect.left());
warnRect.setTop(iconRect.bottom()-17);
warnRect.setWidth(16);
warnRect.setHeight(16);
QIcon warnIcon(":/mirall/resources/warning-16");
QPixmap pm = warnIcon.pixmap(16,16, syncEnabled ? QIcon::Normal : QIcon::Disabled );
painter->drawPixmap(QPoint(warnRect.left(), warnRect.top()),pm );
}
if ((option.state & QStyle::State_Selected)
&& (option.state & QStyle::State_Active)
// Hack: Windows Vista's light blue is not contrasting enough for white
&& !qApp->style()->inherits("QWindowsVistaStyle")) {
painter->setPen(option.palette.color(QPalette::HighlightedText));
} else {
painter->setPen(option.palette.color(QPalette::Text));
}
QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width());
painter->setFont(aliasFont);
painter->drawText(aliasRect, elidedAlias);
painter->setFont(subFont);
QString elidedRemotePathText;
if (remotePath.isEmpty() || remotePath == QLatin1String("/")) {
elidedRemotePathText = subFm.elidedText(tr("Syncing all files in your account with"),
Qt::ElideRight, remotePathRect.width());
} else {
elidedRemotePathText = subFm.elidedText(tr("Remote path: %1").arg(remotePath),
Qt::ElideMiddle, remotePathRect.width());
}
painter->drawText(remotePathRect, elidedRemotePathText);
QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width());
painter->drawText(localPathRect, elidedPathText);
// paint an error overlay if there is an error string
int h = iconRect.bottom();
if( !errorText.isEmpty() ) {
h += aliasMargin;
QRect errorRect = localPathRect;
errorRect.setLeft( iconRect.left());
errorRect.setTop( h );
errorRect.setHeight(subFm.height()+aliasMargin);
errorRect.setRight( option.rect.right()-aliasMargin );
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
painter->drawRoundedRect( errorRect, 4, 4 );
painter->setPen( Qt::white );
painter->setFont(errorFont);
QRect errorTextRect = errorRect;
errorTextRect.setLeft( errorTextRect.left()+aliasMargin +16);
errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 );
int linebreak = errorText.indexOf(QLatin1String("<br"));
QString eText = errorText;
if(linebreak) {
eText = errorText.left(linebreak);
}
painter->drawText(errorTextRect, eText);
h = errorRect.bottom();
}
h += aliasMargin;
// Sync File Progress Bar: Show it if syncFile is not empty.
if( !overallString.isEmpty()) {
int fileNameTextHeight = subFm.boundingRect(tr("File")).height();
int barHeight = qMax(fileNameTextHeight, aliasFm.height()+2); ;
int overallWidth = option.rect.width()-2*aliasMargin;
painter->save();
// Sizes-Text
QRect octetRect = subFm.boundingRect( overallString );
int progressTextWidth = octetRect.width();
// Overall Progress Bar.
QRect pBRect;
pBRect.setTop( h );
pBRect.setLeft( iconRect.left());
pBRect.setHeight(barHeight);
pBRect.setWidth( overallWidth - progressTextWidth - margin );
QStyleOptionProgressBarV2 pBarOpt;
pBarOpt.state = option.state | QStyle::State_Horizontal;
pBarOpt.minimum = 0;
pBarOpt.maximum = 100;
pBarOpt.progress = overallPercent;
pBarOpt.orientation = Qt::Horizontal;
pBarOpt.palette = option.palette;
pBarOpt.rect = pBRect;
QApplication::style()->drawControl( QStyle::CE_ProgressBar, &pBarOpt, painter );
// Overall Progress Text
QRect overallProgressRect;
overallProgressRect.setTop( pBRect.top() );
overallProgressRect.setHeight( pBRect.height() );
overallProgressRect.setLeft( pBRect.right()+margin);
overallProgressRect.setWidth( progressTextWidth );
painter->setFont(progressFont);
QString elidedText = progressFm.elidedText(overallString, Qt::ElideLeft, overallProgressRect.width());
painter->drawText( overallProgressRect, Qt::AlignRight+Qt::AlignVCenter, elidedText);
// painter->drawRect(overallProgressRect);
// Individual File Progress
QRect fileRect;
fileRect.setTop( pBRect.bottom() + margin);
fileRect.setLeft( iconRect.left());
fileRect.setWidth(overallWidth);
fileRect.setHeight(fileNameTextHeight);
elidedText = progressFm.elidedText(itemString, Qt::ElideLeft, fileRect.width());
painter->drawText( fileRect, Qt::AlignLeft+Qt::AlignVCenter, elidedText);
painter->restore();
}
painter->restore();
}
bool FolderStatusDelegate::editorEvent ( QEvent * /*event*/, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/ )
{
return false;
}
} // namespace Mirall
-66
Ver Arquivo
@@ -1,66 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef FOLDERSTATUSMODEL_H
#define FOLDERSTATUSMODEL_H
#include <QStyledItemDelegate>
#include <QStandardItemModel>
namespace Mirall {
class FolderStatusModel : public QStandardItemModel
{
public:
FolderStatusModel();
virtual Qt::ItemFlags flags( const QModelIndex& ) const;
QVariant data(const QModelIndex &index, int role) const;
};
class FolderStatusDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
FolderStatusDelegate();
virtual ~FolderStatusDelegate();
enum datarole { FolderAliasRole = Qt::UserRole + 100,
FolderPathRole,
FolderSecondPathRole,
FolderRemotePath,
FolderStatus,
FolderErrorMsg,
FolderSyncEnabled,
FolderStatusIconRole,
SyncProgressOverallPercent,
SyncProgressOverallString,
SyncProgressItemString,
AddProgressSpace,
WarningCount,
SyncRunning
};
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
const QModelIndex& index );
private:
bool _addProgressSpace;
};
} // namespace Mirall
#endif // FOLDERSTATUSMODEL_H
+9 -3
Ver Arquivo
@@ -69,7 +69,7 @@ QString FolderWatcher::root() const
return _root;
}
void FolderWatcher::addIgnoreListFile( const QString& file )
void FolderWatcher::setIgnoreListFile( const QString& file )
{
if( file.isEmpty() ) return;
@@ -79,12 +79,18 @@ void FolderWatcher::addIgnoreListFile( const QString& file )
while (!infile.atEnd()) {
QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed();
if( !line.startsWith( QLatin1Char('#') ) && line.isEmpty() ) {
_ignores.append(line);
if( !line.startsWith( QLatin1Char('#') )) {
addIgnore(line);
}
}
}
void FolderWatcher::addIgnore(const QString &pattern)
{
if( pattern.isEmpty() ) return;
_ignores.append(pattern);
}
QStringList FolderWatcher::ignores() const
{
return _ignores;
+13 -8
Ver Arquivo
@@ -43,7 +43,7 @@ class FolderWatcherPrivate;
*/
class FolderWatcher : public QObject
{
Q_OBJECT
Q_OBJECT
public:
/**
* @param root Path of the root of the folder
@@ -58,11 +58,16 @@ public:
/**
* Set a file name to load a file with ignore patterns.
*
* Valid entries do not start with a hash sign (#)
* and may contain wildcards
*/
void addIgnoreListFile( const QString& );
void setIgnoreListFile( const QString& );
/**
* Add an ignore pattern that will not be
* notified
*
* You can use wildcards
*/
void addIgnore(const QString &pattern);
/**
* If true, folderChanged() events are sent
@@ -104,10 +109,10 @@ public slots:
void setEventsEnabledDelayed( int );
signals:
/** Emitted when one of the paths is changed */
/**
* Emitted when one of the paths is changed
*/
void folderChanged(const QStringList &pathList);
/** Emitted if an error occurs */
void error(const QString& error);
protected:
void setProcessTimer();
+3 -8
Ver Arquivo
@@ -38,10 +38,10 @@ FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p)
{
_inotify = new INotify(this, standard_event_mask);
slotAddFolderRecursive(_parent->root());
QObject::connect(_inotify, SIGNAL(notifyEvent(int, int, const QString &)),
this, SLOT(slotINotifyEvent(int, int, const QString &)));
QMetaObject::invokeMethod(this, "slotAddFolderRecursive", Q_ARG(QString, _parent->root()));
}
void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
@@ -49,12 +49,7 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
int subdirs = 0;
qDebug() << "(+) Watcher:" << path;
if (!_inotify->addPath(path)) {
FolderWatcher *fw = qobject_cast<FolderWatcher*>(parent());
emit fw->error(tr("Could not monitor directories due to system limitations.\n"
"The application will not work reliably. Please check the\n"
"documentation for possible fixes."));
}
_inotify->addPath(path);
QStringList watchedFolders(_inotify->directories());
// qDebug() << "currently watching " << watchedFolders;
QStringListIterator subfoldersIt(FileUtils::subFoldersList(path, FileUtils::SubFolderRecursive));
@@ -83,7 +78,7 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
qDebug() << " `-> and" << subdirs << "subdirectories";
}
void FolderWatcherPrivate::slotINotifyEvent(int mask, int /*cookie*/, const QString &path)
void FolderWatcherPrivate::slotINotifyEvent(int mask, int cookie, const QString &path)
{
int lastMask = _lastMask;
QString lastPath = _lastPath;
-2
Ver Arquivo
@@ -26,8 +26,6 @@ class FolderWatcherPrivate : public QObject {
Q_OBJECT
public:
FolderWatcherPrivate(FolderWatcher *p);
signals:
void error(const QString& error);
private slots:
void slotAddFolderRecursive(const QString &path);
void slotINotifyEvent(int mask, int cookie, const QString &path);
+119 -123
Ver Arquivo
@@ -19,15 +19,12 @@
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QFileIconProvider>
#include <QInputDialog>
#include <QUrl>
#include <QValidator>
#include <QWizardPage>
#include <QTreeWidget>
#include <QDir>
#include <stdlib.h>
@@ -35,7 +32,7 @@ namespace Mirall
{
FolderWizardSourcePage::FolderWizardSourcePage()
: QWizardPage()
:_folderMap(0)
{
_ui.setupUi(this);
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
@@ -45,6 +42,10 @@ FolderWizardSourcePage::FolderWizardSourcePage()
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
_ui.warnLabel->hide();
#if QT_VERSION >= 0x040700
_ui.localFolderLineEdit->setPlaceholderText(QApplication::translate("FolderWizardSourcePage", "/home/local1", 0, QApplication::UnicodeUTF8));
_ui.aliasLineEdit->setPlaceholderText(QApplication::translate("FolderWizardSourcePage", "Music", 0, QApplication::UnicodeUTF8));
#endif
}
FolderWizardSourcePage::~FolderWizardSourcePage()
@@ -80,11 +81,12 @@ bool FolderWizardSourcePage::isComplete() const
}
// check if the local directory isn't used yet in another ownCloud sync
Folder::Map map = _folderMap;
Folder::Map *map = _folderMap;
if( ! map ) return false;
if( isOk ) {
Folder::Map::const_iterator i = map.constBegin();
while( isOk && i != map.constEnd() ) {
Folder::Map::const_iterator i = map->constBegin();
while( isOk && i != map->constEnd() ) {
Folder *f = static_cast<Folder*>(i.value());
QString folderDir = QDir( f->path() ).canonicalPath();
if( folderDir.isEmpty() )
@@ -123,10 +125,10 @@ bool FolderWizardSourcePage::isComplete() const
isOk = false;
}
Folder::Map::const_iterator i = map.constBegin();
Folder::Map::const_iterator i = map->constBegin();
bool goon = true;
while( goon && i != map.constEnd() ) {
Folder *f = i.value();
while( goon && i != map->constEnd() ) {
Folder *f = static_cast<Folder*>(i.value());
qDebug() << "Checking local alias: " << f->alias();
if( f ) {
if( f->alias() == alias ) {
@@ -166,38 +168,64 @@ void FolderWizardSourcePage::on_localFolderLineEdit_textChanged()
// =================================================================================
FolderWizardTargetPage::FolderWizardTargetPage()
: _warnWasVisible(false)
: _dirChecked( false ),
_warnWasVisible(false)
{
_ui.setupUi(this);
_ui.warnFrame->hide();
connect(_ui.addFolderButton, SIGNAL(clicked()), SLOT(slotAddRemoteFolder()));
connect(_ui.refreshButton, SIGNAL(clicked()), SLOT(slotRefreshFolders()));
connect(_ui.folderTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
connect(_ui.folderTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
registerField(QLatin1String("OCFolderLineEdit"), _ui.OCFolderLineEdit);
connect( _ui.OCFolderLineEdit, SIGNAL(textChanged(QString)),
SLOT(slotFolderTextChanged(QString)));
_timer = new QTimer(this);
_timer->setSingleShot( true );
connect( _timer, SIGNAL(timeout()), SLOT(slotTimerFires()));
}
void FolderWizardTargetPage::slotAddRemoteFolder()
void FolderWizardTargetPage::slotFolderTextChanged( const QString& t)
{
QTreeWidgetItem *current = _ui.folderTreeWidget->currentItem();
_dirChecked = false;
emit completeChanged();
QString parent('/');
if (current) {
parent = current->data(0, Qt::UserRole).toString();
if( t.isEmpty() ) {
_timer->stop();
return;
}
if( _timer->isActive() ) _timer->stop();
_timer->start(500);
}
void FolderWizardTargetPage::slotTimerFires()
{
const QString folder = _ui.OCFolderLineEdit->text();
qDebug() << "Querying folder " << folder;
ownCloudInfo::instance()->getWebDAVPath( folder );
}
void FolderWizardTargetPage::slotDirCheckReply(const QString &url, QNetworkReply *reply)
{
qDebug() << "Got reply from owncloud dir check: " << url << " :" << reply->error();
_dirChecked = (reply->error() == QNetworkReply::NoError);
if( _dirChecked ) {
showWarn();
} else {
showWarn( tr("The folder is not available on your %1.<br/>Click to create it." )
.arg( Theme::instance()->appNameGUI() ), true );
}
QInputDialog *dlg = new QInputDialog(this);
dlg->setWindowTitle(tr("Add Remote Folder"));
dlg->setLabelText(tr("Enter the name of the new folder:"));
dlg->setTextValue(parent);
dlg->open(this, SLOT(slotCreateRemoteFolder(QString)));
dlg->setAttribute(Qt::WA_DeleteOnClose);
emit completeChanged();
}
void FolderWizardTargetPage::slotCreateRemoteFolder(QString folder)
void FolderWizardTargetPage::slotCreateRemoteFolder()
{
const QString folder = _ui.OCFolderLineEdit->text();
if( folder.isEmpty() ) return;
_ui.OCFolderLineEdit->setEnabled( false );
qDebug() << "creating folder on ownCloud: " << folder;
ownCloudInfo::instance()->mkdirRequest( folder );
}
@@ -205,105 +233,32 @@ void FolderWizardTargetPage::slotCreateRemoteFolderFinished( QNetworkReply::Netw
{
qDebug() << "** webdav mkdir request finished " << error;
_ui.OCFolderLineEdit->setEnabled( true );
// the webDAV server seems to return a 202 even if mkdir was successful.
if( error == QNetworkReply::NoError ||
error == QNetworkReply::ContentOperationNotPermittedError) {
showWarn( tr("Folder was successfully created on %1.").arg( Theme::instance()->appNameGUI() ) );
slotRefreshFolders();
showWarn( tr("Folder was successfully created on %1.").arg( Theme::instance()->appNameGUI() ), false );
slotTimerFires();
} else {
showWarn( tr("Failed to create the folder on %1.<br/>Please check manually.").arg( Theme::instance()->appNameGUI() ) );
showWarn( tr("Failed to create the folder on %1.<br/>Please check manually.").arg( Theme::instance()->appNameGUI() ), false );
}
}
static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& text)
{
for (int i = 0; i < parent->childCount(); ++i) {
QTreeWidgetItem *child = parent->child(i);
if (child->text(0) == text) {
return child;
}
}
return 0;
}
static void recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path)
{
QFileIconProvider prov;
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
if (pathTrail.size() == 0) {
if (path.endsWith('/')) {
path.chop(1);
}
parent->setToolTip(0, path);
parent->setData(0, Qt::UserRole, path);
} else {
QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
if (!item) {
item = new QTreeWidgetItem(parent);
item->setIcon(0, folderIcon);
item->setText(0, pathTrail.first());
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
}
pathTrail.removeFirst();
recursiveInsert(item, pathTrail, path);
}
}
void FolderWizardTargetPage::slotUpdateDirectories(QStringList list)
{
QFileIconProvider prov;
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
QString webdavFolder = QUrl(ownCloudInfo::instance()->webdavUrl()).path();
connect(_ui.folderTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(slotItemExpanded(QTreeWidgetItem*)));
QTreeWidgetItem *root = _ui.folderTreeWidget->topLevelItem(0);
if (!root) {
root = new QTreeWidgetItem(_ui.folderTreeWidget);
root->setText(0, tr("Root (\"/\")", "root folder"));
root->setIcon(0, folderIcon);
root->setToolTip(0, tr("Choose this to sync the entire account"));
root->setData(0, Qt::UserRole, "/");
}
foreach (QString path, list) {
path.remove(webdavFolder);
QStringList paths = path.split('/');
if (paths.last().isEmpty()) paths.removeLast();
recursiveInsert(root, paths, path);
}
root->setExpanded(true);
}
void FolderWizardTargetPage::slotRefreshFolders()
{
ownCloudInfo::instance()->getDirectoryListing("/");
_ui.folderTreeWidget->clear();
}
void FolderWizardTargetPage::slotItemExpanded(QTreeWidgetItem *item)
{
ownCloudInfo::instance()->getDirectoryListing(item->text(0));
}
FolderWizardTargetPage::~FolderWizardTargetPage()
{
}
bool FolderWizardTargetPage::isComplete() const
{
if (!_ui.folderTreeWidget->currentItem())
return false;
QString dir = _ui.folderTreeWidget->currentItem()->data(0, Qt::UserRole).toString();
wizard()->setProperty("targetPath", dir);
if( dir == QLatin1String("/") ) {
showWarn( tr("If you sync the root folder, you can <b>not</b> configure another sync directory."));
QString dir = _ui.OCFolderLineEdit->text();
if( dir.isEmpty() || dir == QLatin1String("/") ) {
showWarn( tr("If you sync the root folder, you can <b>not</b> configure another sync directory."), false);
return true;
} else {
showWarn();
return true;
if( _dirChecked ) {
showWarn();
}
return _dirChecked;
}
}
@@ -319,19 +274,53 @@ void FolderWizardTargetPage::initializePage()
/* check the owncloud configuration file and query the ownCloud */
ownCloudInfo *ocInfo = ownCloudInfo::instance();
if( ocInfo->isConfigured() ) {
connect( ocInfo, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
connect( ocInfo, SIGNAL(noOwncloudFound(QNetworkReply*)),
SLOT(slotNoOwnCloudFound(QNetworkReply*)));
connect( ocInfo, SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
SLOT(slotDirCheckReply(QString,QNetworkReply*)));
connect( ocInfo, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
SLOT(slotCreateRemoteFolderFinished( QNetworkReply::NetworkError )));
connect( ocInfo, SIGNAL(directoryListingUpdated(QStringList)),
SLOT(slotUpdateDirectories(QStringList)));
slotRefreshFolders();
connect(_ui._buttCreateFolder, SIGNAL(clicked()), SLOT(slotCreateRemoteFolder()));
ocInfo->checkInstallation();
_ui.OCFolderLineEdit->setEnabled( false );
QString dir = _ui.OCFolderLineEdit->text();
if( !dir.isEmpty() ) {
slotFolderTextChanged( dir );
}
}
}
void FolderWizardTargetPage::slotOwnCloudFound( const QString& url, const QString& infoStr, const QString& version, const QString& edition)
{
Q_UNUSED(version);
Q_UNUSED(edition);
if( infoStr.isEmpty() ) {
} else {
// _ui.OCLabel->setText( tr("to your <a href=\"%1\">%2</a> (version %3)").arg(url)
// .arg(Theme::instance()->appNameGUI()).arg(infoStr));
_ui.OCFolderLineEdit->setEnabled( true );
qDebug() << "ownCloud found on " << url << " with version: " << infoStr;
}
}
void FolderWizardTargetPage::showWarn( const QString& msg ) const
void FolderWizardTargetPage::slotNoOwnCloudFound( QNetworkReply* error )
{
qDebug() << "No ownCloud configured: " << error->error();
// _ui.OCLabel->setText( tr("no configured %1 found!").arg(Theme::instance()->appNameGUI()) );
showWarn( tr("%1 could not be reached:<br/><tt>%2</tt>")
.arg(Theme::instance()->appNameGUI()).arg(error->errorString()));
_ui.OCFolderLineEdit->setEnabled( false );
}
void FolderWizardTargetPage::showWarn( const QString& msg, bool showCreateButton ) const
{
_ui._buttCreateFolder->setVisible( showCreateButton && !msg.isEmpty() );
if( msg.isEmpty() ) {
_ui.warnFrame->hide();
@@ -349,27 +338,34 @@ void FolderWizardTargetPage::showWarn( const QString& msg ) const
FolderWizard::FolderWizard( QWidget *parent )
: QWizard(parent),
_folderWizardSourcePage(new FolderWizardSourcePage),
_folderWizardSourcePage(0),
_folderWizardTargetPage(0)
{
setPage(Page_Source, _folderWizardSourcePage );
_folderWizardSourcePage = new FolderWizardSourcePage();
setPage(Page_Source, _folderWizardSourcePage );
if (!Theme::instance()->singleSyncFolder()) {
_folderWizardTargetPage = new FolderWizardTargetPage();
setPage(Page_Target, _folderWizardTargetPage );
}
setWindowTitle( tr("Add Folder") );
setOptions(QWizard::CancelButtonOnLeft);
setButtonText(QWizard::FinishButton, tr("Add Folder"));
setWindowTitle( tr( "%1 Folder Wizard" ).arg( Theme::instance()->appNameGUI() ) );
#ifdef Q_WS_MAC
setWizardStyle( QWizard::ModernStyle );
#endif
}
FolderWizard::~FolderWizard()
{
delete _folderWizardSourcePage;
if( _folderWizardTargetPage )
delete _folderWizardTargetPage;
}
void FolderWizard::setFolderMap( const Folder::Map& fm)
void FolderWizard::setFolderMap( Folder::Map *fm)
{
if( _folderWizardSourcePage ) {
_folderWizardSourcePage->setFolderMap( fm );
}
}
} // end namespace
+12 -9
Ver Arquivo
@@ -42,14 +42,14 @@ public:
void initializePage();
void cleanupPage();
void setFolderMap( const Folder::Map &fm ) { _folderMap = fm; }
void setFolderMap( Folder::Map *fm ) { _folderMap = fm; }
protected slots:
void on_localFolderChooseBtn_clicked();
void on_localFolderLineEdit_textChanged();
private:
Ui_FolderWizardSourcePage _ui;
Folder::Map _folderMap;
Folder::Map *_folderMap;
};
@@ -70,16 +70,19 @@ public:
virtual void cleanupPage();
protected slots:
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
void slotNoOwnCloudFound(QNetworkReply*);
void showWarn( const QString& = QString() ) const;
void slotAddRemoteFolder();
void slotCreateRemoteFolder(QString);
void slotFolderTextChanged( const QString& );
void slotTimerFires();
void slotDirCheckReply( const QString&, QNetworkReply* );
void showWarn( const QString& = QString(), bool showCreateButton = false ) const;
void slotCreateRemoteFolder();
void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError error );
void slotUpdateDirectories(QStringList);
void slotRefreshFolders();
void slotItemExpanded(QTreeWidgetItem*);
private:
Ui_FolderWizardTargetPage _ui;
QTimer *_timer;
ownCloudInfo *_ownCloudDirCheck;
bool _dirChecked;
bool _warnWasVisible;
@@ -100,7 +103,7 @@ public:
FolderWizard(QWidget *parent = 0);
~FolderWizard();
void setFolderMap( const Folder::Map &map );
void setFolderMap( Folder::Map* );
private:
+28 -16
Ver Arquivo
@@ -7,30 +7,29 @@
<x>0</x>
<y>0</y>
<width>423</width>
<height>155</height>
<height>226</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>349</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Sync Directory</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Pick a local folder on your computer to sync</string>
<string>Pick a local folder on your computer to sync:</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
@@ -67,7 +66,7 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="warnLabel">
<property name="palette">
<palette>
@@ -153,6 +152,19 @@
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>349</width>
<height>83</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
+96 -64
Ver Arquivo
@@ -7,14 +7,93 @@
<x>0</x>
<y>0</y>
<width>520</width>
<height>300</height>
<height>367</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="3" column="0">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<pointsize>14</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Synchronization Target</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Select a destination folder</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Remote folder:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="OCFolderLineEdit"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QFrame" name="warnFrame">
<property name="palette">
<palette>
@@ -112,77 +191,30 @@
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>3</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_buttCreateFolder">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>create</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Select a destination folder</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="addFolderButton">
<property name="text">
<string>Add Folder</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="refreshButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="4">
<widget class="QTreeWidget" name="folderTreeWidget">
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Folders</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -190,7 +222,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
<height>102</height>
</size>
</property>
</spacer>
-97
Ver Arquivo
@@ -1,97 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "generalsettings.h"
#include "ui_generalsettings.h"
#include "mirall/theme.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/application.h"
#include "mirall/utility.h"
#include "mirall/mirallconfigfile.h"
#include <QNetworkProxy>
#include <QDir>
namespace Mirall {
GeneralSettings::GeneralSettings(QWidget *parent) :
QWidget(parent),
_ui(new Ui::GeneralSettings)
{
_ui->setupUi(this);
connect(_ui->desktopNotificationsCheckBox, SIGNAL(toggled(bool)),
SLOT(slotToggleOptionalDesktopNotifications(bool)));
_ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName()));
connect(_ui->autostartCheckBox, SIGNAL(toggled(bool)), SLOT(slotToggleLaunchOnStartup(bool)));
// setup about section
QString about = Theme::instance()->about();
if (about.isEmpty()) {
_ui->aboutGroupBox->hide();
} else {
_ui->aboutLabel->setText(about);
_ui->aboutLabel->setOpenExternalLinks(true);
}
loadMiscSettings();
// misc
connect(_ui->monoIconsCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
// OEM themes are not obliged to ship mono icons, so there
// is no point in offering an option
QString themeDir = QString::fromLatin1(":/mirall/theme/1%1/")
.arg(Theme::instance()->systrayIconFlavor(true));
if (QDir(themeDir).exists())
{
_ui->monoIconsCheckBox->setVisible(false);
}
}
GeneralSettings::~GeneralSettings()
{
delete _ui;
}
void GeneralSettings::loadMiscSettings()
{
MirallConfigFile cfgFile;
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
}
void GeneralSettings::saveMiscSettings()
{
MirallConfigFile cfgFile;
bool isChecked = _ui->monoIconsCheckBox->isChecked();
cfgFile.setMonoIcons(isChecked);
Theme::instance()->setSystrayUseMonoIcons(isChecked);
}
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
{
Theme *theme = Theme::instance();
Utility::setLaunchOnStartup(theme->appName(), theme->appNameGUI(), enable);
}
void GeneralSettings::slotToggleOptionalDesktopNotifications(bool enable)
{
MirallConfigFile cfgFile;
cfgFile.setOptionalDesktopNotifications(enable);
}
} // namespace Mirall
-50
Ver Arquivo
@@ -1,50 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_GENERALSETTINGS_H
#define MIRALL_GENERALSETTINGS_H
#include <QWidget>
namespace Mirall {
namespace Ui {
class GeneralSettings;
}
class GeneralSettings : public QWidget
{
Q_OBJECT
public:
explicit GeneralSettings(QWidget *parent = 0);
~GeneralSettings();
signals:
void proxySettingsChanged();
private slots:
void saveMiscSettings();
void slotToggleLaunchOnStartup(bool);
void slotToggleOptionalDesktopNotifications(bool);
private:
void loadMiscSettings();
Ui::GeneralSettings *_ui;
};
} // namespace Mirall
#endif // MIRALL_GENERALSETTINGS_H
-83
Ver Arquivo
@@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::GeneralSettings</class>
<widget class="QWidget" name="Mirall::GeneralSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>468</width>
<height>169</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="generalGroupBox">
<property name="title">
<string>General</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="autostartCheckBox">
<property name="text">
<string>Launch on System Startup</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="desktopNotificationsCheckBox">
<property name="text">
<string>Show Desktop Notifications</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="monoIconsCheckBox">
<property name="text">
<string>Use Monochrome Icons</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="aboutGroupBox">
<property name="title">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="aboutLabel">
<property name="text">
<string>About</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="proxyButtonGroup"/>
</buttongroups>
</ui>
-167
Ver Arquivo
@@ -1,167 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "mirall/mirallconfigfile.h"
#include "ignorelisteditor.h"
#include "ui_ignorelisteditor.h"
#include <QFile>
#include <QDir>
#include <QListWidget>
#include <QListWidgetItem>
#include <QColorGroup>
#include <QMessageBox>
#include <QInputDialog>
namespace Mirall {
IgnoreListEditor::IgnoreListEditor(QWidget *parent) :
QDialog(parent),
ui(new Ui::IgnoreListEditor)
{
ui->setupUi(this);
ui->descriptionLabel->setText(tr("Files or directories matching a pattern will not be synchronized.\n\n"
"Checked items will also be deleted if they prevent a directory from "
"being removed. This is useful for meta data."));
MirallConfigFile cfgFile;
readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::SystemScope), true);
readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::UserScope), false);
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
ui->removePushButton->setEnabled(false);
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemChanged(QListWidgetItem*)));
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
}
static void setupItemFlags(QListWidgetItem* item)
{
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
}
IgnoreListEditor::~IgnoreListEditor()
{
delete ui;
}
void IgnoreListEditor::slotItemSelectionChanged()
{
QListWidgetItem *item = ui->listWidget->currentItem();
if (!item) {
ui->removePushButton->setEnabled(false);
return;
}
bool enable = item->flags() & Qt::ItemIsEnabled;
ui->removePushButton->setEnabled(enable);
}
void IgnoreListEditor::slotRemoveCurrentItem()
{
delete ui->listWidget->currentItem();
}
void IgnoreListEditor::slotUpdateLocalIgnoreList()
{
MirallConfigFile cfgFile;
QString ignoreFile = cfgFile.excludeFile(MirallConfigFile::UserScope);
QFile ignores(ignoreFile);
if (ignores.open(QIODevice::WriteOnly)) {
for(int i = 0; i < ui->listWidget->count(); ++i) {
QListWidgetItem *item = ui->listWidget->item(i);
if (item->flags() & Qt::ItemIsEnabled) {
QByteArray prepend;
if (item->checkState() == Qt::Checked) {
prepend = "]";
}
ignores.write(prepend+item->text().toUtf8()+'\n');
}
}
} else {
QMessageBox::warning(this, tr("Could not open file"),
tr("Cannot write changes to '%1'.").arg(ignoreFile));
}
}
void IgnoreListEditor::slotAddPattern()
{
bool okClicked;
QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"),
tr("Add a new ignore pattern:"),
QLineEdit::Normal, QString(), &okClicked);
if (!okClicked || pattern.isEmpty())
return;
QListWidgetItem *item = new QListWidgetItem;
setupItemFlags(item);
if (pattern.startsWith("]")) {
pattern = pattern.mid(1);
item->setCheckState(Qt::Checked);
}
item->setText(pattern);
ui->listWidget->addItem(item);
ui->listWidget->scrollToItem(item);
}
void IgnoreListEditor::slotEditPattern(QListWidgetItem *item)
{
if (!(item->flags() & Qt::ItemIsEnabled))
return;
QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"),
tr("Add a new ignore pattern:"),
QLineEdit::Normal, item->text());
if (!pattern.isEmpty()) {
item->setText(pattern);
}
}
void IgnoreListEditor::readIgnoreFile(const QString &file, bool readOnly)
{
MirallConfigFile cfgFile;
const QString disabledTip(tr("This entry is provided by the system at '%1' "
"and cannot be modified in this view.")
.arg(QDir::toNativeSeparators(cfgFile.excludeFile(MirallConfigFile::SystemScope))));
QFile ignores(file);
if (ignores.open(QIODevice::ReadOnly)) {
while (!ignores.atEnd()) {
QString line = QString::fromUtf8(ignores.readLine());
line.chop(1);
if (!line.isEmpty() && !line.startsWith("#")) {
QListWidgetItem *item = new QListWidgetItem;
setupItemFlags(item);
if (line.startsWith("]")) {
line = line.mid(1);
item->setCheckState(Qt::Checked);
}
item->setText(line);
if (readOnly) {
item->setFlags(item->flags() ^ Qt::ItemIsEnabled);
item->setToolTip(disabledTip);
}
ui->listWidget->addItem(item);
}
}
}
}
} // namespace Mirall
-49
Ver Arquivo
@@ -1,49 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IGNORELISTEDITOR_H
#define IGNORELISTEDITOR_H
#include <QDialog>
class QListWidgetItem;
namespace Mirall {
namespace Ui {
class IgnoreListEditor;
}
class IgnoreListEditor : public QDialog
{
Q_OBJECT
public:
explicit IgnoreListEditor(QWidget *parent = 0);
~IgnoreListEditor();
private slots:
void slotItemSelectionChanged();
void slotRemoveCurrentItem();
void slotUpdateLocalIgnoreList();
void slotAddPattern();
void slotEditPattern(QListWidgetItem*);
private:
void readIgnoreFile(const QString& file, bool readOnly);
Ui::IgnoreListEditor *ui;
};
} // namespace Mirall
#endif // IGNORELISTEDITOR_H
-117
Ver Arquivo
@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::IgnoreListEditor</class>
<widget class="QDialog" name="Mirall::IgnoreListEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>471</width>
<height>359</height>
</rect>
</property>
<property name="windowTitle">
<string>Ignored Files Editor</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>213</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" rowspan="3">
<widget class="QListWidget" name="listWidget">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="addPushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="removePushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="descriptionLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Mirall::IgnoreListEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>348</x>
<y>333</y>
</hint>
<hint type="destinationlabel">
<x>361</x>
<y>355</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Mirall::IgnoreListEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>210</x>
<y>333</y>
</hint>
<hint type="destinationlabel">
<x>385</x>
<y>297</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+5 -8
Ver Arquivo
@@ -47,7 +47,7 @@ INotify::INotify(QObject *parent, int mask)
_buffer = (char *) malloc(_buffer_size);
}
void INotify::slotActivated(int /*fd*/)
void INotify::slotActivated(int fd)
{
int len;
struct inotify_event* event;
@@ -82,7 +82,7 @@ void INotify::slotActivated(int /*fd*/)
// reset counter
i = 0;
// while there are enough events in the buffer
while(i + sizeof(struct inotify_event) < static_cast<unsigned int>(len)) {
while(i + sizeof(struct inotify_event) < len) {
// cast an inotify_event
event = (struct inotify_event*)&_buffer[i];
// with the help of watch descriptor, retrieve, corresponding INotify
@@ -115,17 +115,14 @@ INotify::~INotify()
delete _notifier;
}
bool INotify::addPath(const QString &path)
void INotify::addPath(const QString &path)
{
// Add an inotify watch.
int wd = inotify_add_watch(_fd, path.toUtf8().constData(), _mask);
if( wd > -1 ) {
if( wd > -1 )
_wds[path] = wd;
return true;
} else {
else
qDebug() << "WRN: Could not watch " << path << ':' << strerror(errno);
return false;
}
}
void INotify::removePath(const QString &path)
+4 -1
Ver Arquivo
@@ -38,7 +38,10 @@ public:
INotify(QObject *parent, int mask);
~INotify();
bool addPath(const QString &name);
static void initialize();
static void cleanup();
void addPath(const QString &name);
void removePath(const QString &name);
QStringList directories() const;
-333
Ver Arquivo
@@ -1,333 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QtGui>
#include "mirall/itemprogressdialog.h"
#include "mirall/syncresult.h"
#include "mirall/logger.h"
#include "mirall/utility.h"
#include "mirall/theme.h"
#include "mirall/folderman.h"
#include "mirall/syncfileitem.h"
#include "ui_itemprogressdialog.h"
namespace Mirall {
ItemProgressDialog::ItemProgressDialog(Application*, QWidget *parent) :
QDialog(parent),
ErrorIndicatorRole( Qt::UserRole +1 ),
_ui(new Ui::ItemProgressDialog)
{
_ui->setupUi(this);
connect(_ui->_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(accept()));
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,Progress::Info)),
this, SLOT(slotProgressInfo(QString,Progress::Info)));
connect(ProgressDispatcher::instance(), SIGNAL(progressSyncProblem(const QString&,const Progress::SyncProblem&)),
this, SLOT(slotProgressErrors(const QString&, const Progress::SyncProblem&)));
QStringList header;
header << tr("Time");
header << tr("File");
header << tr("Folder");
header << tr("Action");
header << tr("Size");
_ui->_treeWidget->setHeaderLabels( header );
_ui->_treeWidget->setColumnWidth(1, 180);
_ui->_treeWidget->setColumnCount(5);
_ui->_treeWidget->setRootIsDecorated(false);
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
setWindowTitle(tr("Sync Protocol"));
}
void ItemProgressDialog::setSyncResultStatus(const SyncResult& result )
{
if( result.errorStrings().count() ) {
_ui->_errorLabel->setVisible(true);
_ui->_errorLabel->setTextFormat(Qt::RichText);
QString errStr;
QStringList errors = result.errorStrings();
int cnt = errors.size();
bool appendDots = false;
if( cnt > 3 ) {
cnt = 3;
appendDots = true;
}
for( int i = 0; i < cnt; i++) {
errStr.append(QString("%1<br/>").arg(errors.at(i)));
}
if( appendDots ) {
errStr.append(QString("..."));
}
_ui->_errorLabel->setText(errStr);
} else {
_ui->_errorLabel->setText(QString::null);
_ui->_errorLabel->setVisible(false);
}
}
void ItemProgressDialog::setSyncResult( const SyncResult& result )
{
setSyncResultStatus(result);
const QString& folder = result.folder();
qDebug() << "Setting sync result for folder " << folder;
SyncFileItemVector::const_iterator i;
const SyncFileItemVector& items = result.syncFileItemVector();
QDateTime dt = QDateTime::currentDateTime();
for (i = items.begin(); i != items.end(); ++i) {
const SyncFileItem& item = *i;
QString errMsg;
QString tooltip;
// handle ignored files here.
if( item._instruction == CSYNC_INSTRUCTION_IGNORE
|| item._instruction == CSYNC_INSTRUCTION_CONFLICT ) {
QStringList columns;
QString timeStr = timeString(dt);
QString longTimeStr = timeString(dt, QLocale::LongFormat);
columns << timeStr;
columns << item._file;
columns << folder;
if( item._instruction == CSYNC_INSTRUCTION_IGNORE) {
if( item._type == SyncFileItem::File ) {
errMsg = tr("File ignored.");
tooltip = tr("The file was ignored because it is listed in the clients ignore list\n"
"or the filename contains characters that are not syncable\nin a cross platform "
"environment.");
} else if( item._type == SyncFileItem::Directory ){
errMsg = tr("Directory ignored.");
tooltip = tr("The directory was ignored because it is listed in the clients\nignore list "
"or the directory name contains\ncharacters that are not syncable in a cross "
"platform environment.");
} else if( item._type == SyncFileItem::SoftLink ) {
errMsg = tr("Soft Link ignored.");
tooltip = tr("Softlinks break the semantics of synchronization.\nPlease do not "
"use them in synced directories.");
} else {
errMsg = tr("Ignored.");
}
} else if( item._instruction == CSYNC_INSTRUCTION_CONFLICT ) {
errMsg = tr("Conflict file.");
tooltip = tr("The file was changed on server and local repository and as a result it\n"
"created a so called conflict. The local change is copied to the conflict\n"
"file while the file from the server side is available under the original\n"
"name");
} else {
Q_ASSERT(!"unhandled instruction.");
}
columns << errMsg;
QTreeWidgetItem *twitem = new QTreeWidgetItem(columns);
twitem->setData(0, ErrorIndicatorRole, QVariant(true) );
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(3, tooltip);
twitem->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Problem, true));
_ui->_treeWidget->addTopLevelItem(twitem);
}
}
}
void ItemProgressDialog::setupList()
{
// get the folders to set up the top level list.
Folder::Map map = FolderMan::instance()->map();
SyncResult lastResult;
QDateTime dt;
bool haveSyncResult = false;
foreach( Folder *f, map.values() ) {
if( f->syncResult().syncTime() > dt ) {
dt = f->syncResult().syncTime();
lastResult = f->syncResult();
haveSyncResult = true;
}
}
if( haveSyncResult ) {
setSyncResult(lastResult);
}
QList<Progress::Info> progressList = ProgressDispatcher::instance()->recentChangedItems(0); // All.
QHash <QString, int> folderHash;
foreach( Progress::Info info, progressList ) {
slotProgressInfo( info.folder, info );
folderHash[info.folder] = 1;
}
QList<Progress::SyncProblem> problemList = ProgressDispatcher::instance()->recentProblems(0);
foreach( Progress::SyncProblem prob, problemList ) {
slotProgressErrors(prob.folder, prob);
folderHash[prob.folder] = 1;
}
}
ItemProgressDialog::~ItemProgressDialog()
{
delete _ui;
}
void ItemProgressDialog::copyToClipboard()
{
QString text;
QTextStream ts(&text);
int topLevelItems = _ui->_treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(i);
ts << left << qSetFieldWidth(0)
<< item->data(0, Qt::DisplayRole).toString()
<< endl;
int childItems = item->childCount();
for (int j = 0; j < childItems; j++) {
QTreeWidgetItem *child =item->child(j);
// time stamp
ts << left << qSetFieldWidth(10)
<< child->data(0,Qt::DisplayRole).toString()
// file name
<< qSetFieldWidth(50)
<< child->data(1,Qt::DisplayRole).toString()
// action
<< qSetFieldWidth(15)
<< child->data(2, Qt::DisplayRole).toString()
// size
<< qSetFieldWidth(10)
<< child->data(3, Qt::DisplayRole).toString()
<< qSetFieldWidth(0)
<< endl;
}
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
}
void ItemProgressDialog::accept()
{
QDialog::accept();
}
void ItemProgressDialog::cleanErrors( const QString& /* folder */ ) // FIXME: Use the folder to detect which errors can be deleted.
{
_problemCounter = 0;
QList<QTreeWidgetItem*> wipeList;
int itemCnt = _ui->_treeWidget->topLevelItemCount();
for( int cnt = 0; cnt < itemCnt; cnt++ ) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
bool isErrorItem = item->data(0, ErrorIndicatorRole).toBool();
if( isErrorItem ) {
wipeList.append(item);
}
}
qDeleteAll(wipeList.begin(), wipeList.end());
}
QString ItemProgressDialog::timeString(QDateTime dt, QLocale::FormatType format) const
{
QLocale loc = QLocale::system();
QString timeStr;
QDate today = QDate::currentDate();
if( format == QLocale::NarrowFormat ) {
if( dt.date().day() == today.day() ) {
timeStr = loc.toString(dt.time(), QLocale::NarrowFormat);
} else {
timeStr = loc.toString(dt, QLocale::NarrowFormat);
}
} else {
timeStr = loc.toString(dt, format);
}
return timeStr;
}
void ItemProgressDialog::slotProgressErrors( const QString& folder, const Progress::SyncProblem& problem )
{
QStringList columns;
QString timeStr = timeString(problem.timestamp);
QString longTimeStr = timeString(problem.timestamp, QLocale::LongFormat);
columns << timeStr;
columns << problem.current_file;
columns << folder;
QString errMsg = tr("Problem: %1").arg(problem.error_message);
#if 0
if( problem.error_code == 507 ) {
errMsg = tr("No more storage space available on server.");
}
#endif
columns << errMsg;
QTreeWidgetItem *item = new QTreeWidgetItem(columns);
item->setData(0, ErrorIndicatorRole, QVariant(true) );
// Maybe we should not set the error icon for all problems but distinguish
// by error_code. A quota problem is considered an error, others might not??
item->setIcon(0, Theme::instance()->syncStateIcon(SyncResult::Error, true));
item->setToolTip(0, longTimeStr);
_ui->_treeWidget->addTopLevelItem(item);
Q_UNUSED(item);
}
void ItemProgressDialog::slotProgressInfo( const QString& folder, const Progress::Info& progress )
{
if( progress.kind == Progress::StartSync ) {
cleanErrors( folder );
}
if( progress.kind == Progress::EndSync ) {
// decorateFolderItem( folder );
}
// Ingore other events than finishing an individual up- or download.
if( !(progress.kind == Progress::EndDownload || progress.kind == Progress::EndUpload || progress.kind == Progress::EndDelete)) {
return;
}
QStringList columns;
QString timeStr = timeString(progress.timestamp);
QString longTimeStr = timeString(progress.timestamp, QLocale::LongFormat);
columns << timeStr;
columns << progress.current_file;
columns << progress.folder;
columns << Progress::asResultString(progress.kind);
columns << Utility::octetsToString( progress.file_size );
QTreeWidgetItem *item = new QTreeWidgetItem(columns);
item->setToolTip(0, longTimeStr);
_ui->_treeWidget->addTopLevelItem(item);
Q_UNUSED(item);
}
}
+8 -31
Ver Arquivo
@@ -28,8 +28,6 @@
#include <QMessageBox>
#include <QCoreApplication>
#include <QDebug>
#include <QSettings>
#include <QAction>
#include "mirall/mirallconfigfile.h"
#include "mirall/logger.h"
@@ -46,6 +44,11 @@ LogWidget::LogWidget(QWidget *parent)
font.setFamily(QLatin1String("Courier New"));
font.setFixedPitch(true);
document()->setDefaultFont( font );
MirallConfigFile cfg;
int lines = cfg.maxLogLines();
// qDebug() << "# ## Have " << lines << " Loglines!";
document()->setMaximumBlockCount( lines );
}
// ==============================================================================
@@ -53,9 +56,9 @@ LogWidget::LogWidget(QWidget *parent)
LogBrowser::LogBrowser(QWidget *parent) :
QDialog(parent),
_logWidget( new LogWidget(parent) ),
_logstream(0),
_doFileFlush(false)
{
setObjectName("LogBrowser"); // for save/restoreGeometry()
setWindowTitle(tr("Log Output"));
setMinimumWidth(600);
@@ -112,18 +115,6 @@ LogBrowser::LogBrowser(QWidget *parent) :
// Direct connection for log comming from this thread, and queued for the one in a different thread
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
QAction *showLogWindow = new QAction(this);
showLogWindow->setShortcut(QKeySequence("F12"));
connect(showLogWindow, SIGNAL(triggered()), SLOT(close()));
addAction(showLogWindow);
MirallConfigFile cfg;
cfg.restoreGeometry(this);
int lines = cfg.maxLogLines();
// qDebug() << "# ## Have " << lines << " Loglines!";
_logWidget->document()->setMaximumBlockCount( lines );
}
LogBrowser::~LogBrowser()
@@ -147,16 +138,9 @@ void LogBrowser::setLogFile( const QString & name, bool flush )
if( _logstream ) {
_logFile.close();
}
_logFile.setFileName( name );
bool openSucceeded = false;
if (name == QLatin1String("-")) {
openSucceeded = _logFile.open(1, QIODevice::WriteOnly);
} else {
_logFile.setFileName( name );
openSucceeded = _logFile.open(QIODevice::WriteOnly);
}
if(!openSucceeded) {
if(!_logFile.open(QIODevice::WriteOnly)) {
QMessageBox::warning(
this,
tr("Error"),
@@ -227,11 +211,4 @@ void LogBrowser::slotClearLog()
_logWidget->clear();
}
void LogBrowser::closeEvent(QCloseEvent *event)
{
MirallConfigFile cfg;
cfg.saveGeometry(this);
QWidget::closeEvent(event);
}
} // namespace
+3 -2
Ver Arquivo
@@ -47,8 +47,9 @@ public:
void setLogFile(const QString& , bool );
protected:
void closeEvent(QCloseEvent *event);
signals:
public slots:
protected slots:
void slotNewLog( const QString &msg );
+1 -15
Ver Arquivo
@@ -22,6 +22,7 @@ Logger::Logger( QObject* parent)
: QObject(parent),
_showTime(true)
{
}
Logger *Logger::instance()
@@ -38,21 +39,6 @@ void Logger::destroy()
}
}
void Logger::postGuiLog(const QString &title, const QString &message)
{
emit guiLog(title, message);
}
void Logger::postOptionalGuiLog(const QString &title, const QString &message)
{
emit optionalGuiLog(title, message);
}
void Logger::postGuiMessage(const QString &title, const QString &message)
{
emit postGuiMessage(title, message);
}
void Logger::log(Log log)
{
QString msg;
-6
Ver Arquivo
@@ -46,15 +46,9 @@ public:
static Logger* instance();
static void destroy();
void postGuiLog(const QString& title, const QString& message);
void postOptionalGuiLog(const QString& title, const QString& message);
void postGuiMessage(const QString& title, const QString& message);
signals:
void newLog(const QString&);
void guiLog(const QString&, const QString&);
void guiMessage(const QString&, const QString&);
void optionalGuiLog(const QString&, const QString&);
protected:
Logger(QObject* parent=0);
-34
Ver Arquivo
@@ -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 <QNetworkRequest>
#include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h"
namespace Mirall
{
MirallAccessManager::MirallAccessManager(QObject* parent)
: QNetworkAccessManager (parent)
{}
QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
QNetworkRequest newRequest(request);
newRequest.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString());
return QNetworkAccessManager::createRequest (op, newRequest, outgoingData);
}
} // ns Mirall
-35
Ver Arquivo
@@ -1,35 +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_ACCESS_MANAGER_H
#define MIRALL_ACCESS_MANAGER_H
#include <QNetworkAccessManager>
namespace Mirall
{
class MirallAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
MirallAccessManager(QObject* parent = 0);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
};
} // ns Mirall
#endif
+232 -311
Ver Arquivo
@@ -18,192 +18,97 @@
#include "mirall/owncloudinfo.h"
#include "mirall/owncloudtheme.h"
#include "mirall/theme.h"
#include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h"
#include "mirall/credentialstore.h"
#include <QtCore>
#include <QtGui>
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
#define DEFAULT_MAX_LOG_LINES 20000
#define CA_CERTS_KEY QLatin1String("CaCertificates")
namespace Mirall {
static const char urlC[] = "url";
static const char authTypeC[] = "authType";
static const char caCertsKeyC[] = "CaCertificates";
static const char remotePollIntervalC[] = "remotePollInterval";
static const char forceSyncIntervalC[] = "forceSyncInterval";
static const char monoIconsC[] = "monoIcons";
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char geometryC[] = "geometry";
static const char proxyHostC[] = "Proxy/host";
static const char proxyTypeC[] = "Proxy/type";
static const char proxyPortC[] = "Proxy/port";
static const char proxyUserC[] = "Proxy/user";
static const char proxyPassC[] = "Proxy/pass";
static const char proxyNeedsAuthC[] = "Proxy/needsAuth";
static const char useUploadLimitC[] = "BWLimit/useUploadLimit";
static const char useDownloadLimitC[] = "BWLimit/useDownloadLimit";
static const char uploadLimitC[] = "BWLimit/uploadLimit";
static const char downloadLimitC[] = "BWLimit/downloadLimit";
static const char seenVersionC[] = "Updater/seenVersion";
static const char maxLogLinesC[] = "Logging/maxLogLines";
QString MirallConfigFile::_oCVersion;
QString MirallConfigFile::_confDir = QString::null;
bool MirallConfigFile::_askedUser = false;
QMap< QString, MirallConfigFile::SharedCreds > MirallConfigFile::credentialsPerConfig;
MirallConfigFile::MirallConfigFile( const QString& appendix, bool useOldConfig )
MirallConfigFile::MirallConfigFile( const QString& appendix )
:_customHandle(appendix)
{
if (useOldConfig && !appendix.isEmpty()) {
QString oldConfigFile = configFile();
_customHandle = appendix;
QString newConfigFile = configFile();
QFile::copy(oldConfigFile, newConfigFile);
} else {
_customHandle = appendix;
}
QSettings::setDefaultFormat(QSettings::IniFormat);
if (! credentialsPerConfig.contains(_customHandle)) {
QString con( _customHandle );
if( _customHandle.isEmpty() ) con = defaultConnection();
const QString config = configFile();
qDebug() << "Loading config: " << config;
QSettings settings(config, QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.beginGroup( con );
QString type = settings.value( QLatin1String(authTypeC) ).toString();
qDebug() << "Getting credentials of type " << type << " for " << _customHandle;
credentialsPerConfig.insert(_customHandle, SharedCreds(CredentialsFactory::create (type)));
}
}
void MirallConfigFile::setConfDir(const QString &value)
{
QString dirPath = value;
if( dirPath.isEmpty() ) return;
if( value.isEmpty() ) return;
QFileInfo fi(dirPath);
if ( !fi.exists() && !fi.isAbsolute() ) {
QDir::current().mkdir(dirPath);
QDir dir = QDir::current();
dir.cd(dirPath);
fi.setFile(dir.path());
}
QFileInfo fi(value);
if( fi.exists() && fi.isDir() ) {
dirPath = fi.absoluteFilePath();
qDebug() << "** Using custom config dir " << dirPath;
_confDir=dirPath;
qDebug() << "** Using custom config dir " << value;
_confDir=value;
}
}
bool MirallConfigFile::optionalDesktopNotifications() const
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool();
}
void MirallConfigFile::setOptionalDesktopNotifications(bool show)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.setValue(QLatin1String(optionalDesktopNoficationsC), show);
settings.sync();
}
QString MirallConfigFile::seenVersion() const
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
return settings.value(QLatin1String(seenVersionC)).toString();
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(QLatin1String("Updater"));
return settings.value(QLatin1String("seenVersion")).toString();
}
void MirallConfigFile::setSeenVersion(const QString &version)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.setValue(QLatin1String(seenVersionC), version);
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(QLatin1String("Updater"));
settings.setValue(QLatin1String("seenVersion"), version);
settings.sync();
}
void MirallConfigFile::saveGeometry(QWidget *w)
{
Q_ASSERT(!w->objectName().isNull());
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.beginGroup(w->objectName());
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
settings.sync();
}
void MirallConfigFile::restoreGeometry(QWidget *w)
{
w->restoreGeometry(getValue(geometryC, w->objectName()).toByteArray());
}
QString MirallConfigFile::configPath() const
{
if( _confDir.isEmpty() ) {
_confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
}
QString dir = _confDir;
if( _confDir.isEmpty() )
_confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
if( !dir.endsWith(QLatin1Char('/')) ) dir.append(QLatin1Char('/'));
return dir;
}
QString MirallConfigFile::excludeFile(Scope scope) const
QString MirallConfigFile::excludeFile() const
{
// prefer sync-exclude.lst, but if it does not exist, check for
// exclude.lst for compatibility reasons in the user writeable
// exclude.lst for compatibility reasonsin the user writeable
// directories.
const QString exclFile("sync-exclude.lst");
QFileInfo fi;
fi.setFile( configPath(), exclFile );
if (scope != SystemScope) {
fi.setFile( configPath(), exclFile );
if( ! fi.isReadable() ) {
fi.setFile( configPath(), QLatin1String("exclude.lst") );
}
if( ! fi.isReadable() ) {
fi.setFile( configPath(), exclFile );
}
if( ! fi.isReadable() ) {
fi.setFile( configPath(), QLatin1String("exclude.lst") );
}
if (scope != UserScope) {
// Check alternative places...
if( ! fi.isReadable() ) {
#ifdef Q_OS_WIN
fi.setFile( QApplication::applicationDirPath(), exclFile );
// Check alternative places...
if( ! fi.isReadable() ) {
#ifdef Q_OS_WIN32
fi.setFile( QApplication::applicationDirPath(), exclFile );
#endif
#ifdef Q_OS_UNIX
fi.setFile( QString("/etc/%1").arg(Theme::instance()->appName()), exclFile );
#ifdef Q_OS_LINUX
fi.setFile( QString("/etc/%1").arg(Theme::instance()->appName()), exclFile );
#endif
#ifdef Q_OS_MAC
// exec path is inside the bundle
fi.setFile( QApplication::applicationDirPath(),
QLatin1String("../Resources/") + exclFile );
// exec path is inside the bundle
fi.setFile( QApplication::applicationDirPath(),
QLatin1String("../Resources/") + exclFile );
#endif
}
}
qDebug() << " ==> returning exclude file path: " << fi.absoluteFilePath();
return fi.absoluteFilePath();
if( fi.isReadable() ) {
qDebug() << " ==> returning exclude file path: " << fi.absoluteFilePath();
return fi.absoluteFilePath();
}
qDebug() << "EMPTY exclude file path!";
return QString::null;
}
@@ -213,13 +118,13 @@ QString MirallConfigFile::configFile() const
if( qApp->applicationName().isEmpty() ) {
qApp->setApplicationName( Theme::instance()->appNameGUI() );
}
QString file = configPath() + Theme::instance()->configFileName();
QString dir = configPath() + Theme::instance()->configFileName();
if( !_customHandle.isEmpty() ) {
file.append( QLatin1Char('_'));
file.append( _customHandle );
qDebug() << __PRETTY_FUNCTION__ << " OO Custom config file in use: " << file;
dir.append( QLatin1Char('_'));
dir.append( _customHandle );
qDebug() << " OO Custom config file in use: " << dir;
}
return file;
return dir;
}
bool MirallConfigFile::exists()
@@ -238,92 +143,122 @@ bool MirallConfigFile::connectionExists( const QString& conn )
QString con = conn;
if( conn.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.beginGroup(conn);
return settings.contains( QLatin1String(urlC) );
return settings.contains( QString::fromLatin1("%1/url").arg( conn ) );
}
void MirallConfigFile::writeOwncloudConfig( const QString& connection,
const QString& url,
AbstractCredentials* credentials)
const QString& user,
const QString& passwd )
{
const QString file = configFile();
qDebug() << "*** writing mirall config to " << file;
bool skipPwd = false; // can be refactored - remove it.
qDebug() << "*** writing mirall config to " << file << " Skippwd: " << skipPwd;
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( file, QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.beginGroup( connection );
settings.setValue( QLatin1String(urlC), url );
settings.setValue(QLatin1String(authTypeC), credentials->authType());
credentialsPerConfig.insert(_customHandle, SharedCreds(credentials));
settings.setValue( QLatin1String("url"), url );
settings.setValue( QLatin1String("user"), user );
#ifdef WITH_QTKEYCHAIN
// Password is stored to QtKeyChain now by default in CredentialStore
// The CredentialStore calls clearPasswordFromConfig after the creds
// were successfully wiritten to delete the passwd entry from config.
qDebug() << "Going to delete the password from settings file.";
#else
if( !skipPwd )
writePassword( passwd );
#endif
if( !skipPwd )
writePassword( passwd );
else
clearPasswordFromConfig(); // wipe the password.
settings.setValue( QLatin1String("nostoredpassword"), QVariant(skipPwd) );
settings.sync();
// check the perms, only read-write for the owner.
QFile::setPermissions( file, QFile::ReadOwner|QFile::WriteOwner );
// Store credentials temporar until the config is finalized.
//ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle );
ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle );
}
void MirallConfigFile::storeData(const QString& group, const QString& key, const QVariant& value)
// This method is called after the password was successfully stored into the
// QKeyChain in CredentialStore.
void MirallConfigFile::clearPasswordFromConfig( const QString& connection )
{
const QString con(group.isEmpty() ? defaultConnection() : group);
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
const QString file = configFile();
QString con( defaultConnection() );
if( !connection.isEmpty() )
con = connection;
settings.beginGroup(con);
settings.setValue(key, value);
QSettings settings( file, QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
settings.remove(QLatin1String("passwd"));
settings.remove(QLatin1String("password"));
settings.sync();
}
QVariant MirallConfigFile::retrieveData(const QString& group, const QString& key) const
bool MirallConfigFile::writePassword( const QString& passwd, const QString& connection )
{
const QString con(group.isEmpty() ? defaultConnection() : group);
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
const QString file = configFile();
QString pwd( passwd );
QString con( defaultConnection() );
if( !connection.isEmpty() )
con = connection;
settings.beginGroup(con);
return settings.value(key);
QSettings settings( file, QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
// store password into settings file.
settings.beginGroup( con );
QByteArray pwdba = pwd.toUtf8();
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
settings.sync();
return true;
}
void MirallConfigFile::removeData(const QString& group, const QString& key)
// set the url, called from redirect handling.
void MirallConfigFile::setOwnCloudUrl( const QString& connection, const QString & url )
{
const QString con(group.isEmpty() ? defaultConnection() : group);
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
const QString file = configFile();
settings.beginGroup(con);
settings.remove(key);
}
QSettings settings( file, QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.beginGroup( connection );
settings.setValue( QLatin1String("url"), url );
bool MirallConfigFile::dataExists(const QString& group, const QString& key) const
{
const QString con(group.isEmpty() ? defaultConnection() : group);
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.beginGroup(con);
return settings.contains(key);
settings.sync();
}
QByteArray MirallConfigFile::caCerts( )
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
return settings.value( QLatin1String(caCertsKeyC) ).toByteArray();
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
QByteArray certs = settings.value( CA_CERTS_KEY ).toByteArray();
return certs;
}
void MirallConfigFile::setCaCerts( const QByteArray & certs )
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
const QString file = configFile();
QSettings settings( file, QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.setValue( QLatin1String(caCertsKeyC), certs );
settings.setValue( CA_CERTS_KEY, certs );
settings.sync();
}
@@ -336,8 +271,7 @@ void MirallConfigFile::removeConnection( const QString& connection )
qDebug() << " removing the config file for connection " << con;
// Currently its just removing the entire config file
// TODO: Eh? Shouldn't it try to load a file under configFile() and set it to INI?
QSettings settings;
QSettings settings( configFile(), QSettings::IniFormat);
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
settings.remove(QString::null); // removes all content from the group
@@ -348,22 +282,41 @@ void MirallConfigFile::removeConnection( const QString& connection )
* returns the configured owncloud url if its already configured, otherwise an empty
* string.
* The returned url always has a trailing hash.
* If webdav is true, the webdav-server url is returned.
*/
QString MirallConfigFile::ownCloudUrl( const QString& connection) const
QString MirallConfigFile::ownCloudUrl( const QString& connection, bool webdav ) const
{
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
QString url = settings.value( QLatin1String(urlC) ).toString();
QString url = settings.value( QLatin1String("url") ).toString();
if( ! url.isEmpty() ) {
if( ! url.endsWith(QLatin1Char('/'))) url.append(QLatin1String("/"));
if( webdav ) url.append( QLatin1String("remote.php/webdav/") );
}
return url;
qDebug() << "Returning configured owncloud url: " << url;
return url;
}
QString MirallConfigFile::ownCloudUser( const QString& connection ) const
{
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
QString user = settings.value( QLatin1String("user") ).toString();
// qDebug() << "Returning configured owncloud user: " << user;
return user;
}
int MirallConfigFile::remotePollInterval( const QString& connection ) const
@@ -371,11 +324,11 @@ int MirallConfigFile::remotePollInterval( const QString& connection ) const
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
int remoteInterval = settings.value( QLatin1String(remotePollIntervalC), DEFAULT_REMOTE_POLL_INTERVAL ).toInt();
int remoteInterval = settings.value( QLatin1String("remotePollInterval"), DEFAULT_REMOTE_POLL_INTERVAL ).toInt();
if( remoteInterval < 5000) {
qDebug() << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL;
remoteInterval = DEFAULT_REMOTE_POLL_INTERVAL;
@@ -392,29 +345,52 @@ void MirallConfigFile::setRemotePollInterval(int interval, const QString &connec
qDebug() << "Remote Poll interval of " << interval << " is below fife seconds.";
return;
}
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
settings.setValue(QLatin1String(remotePollIntervalC), interval );
settings.setValue("remotePollInterval", interval );
settings.sync();
}
quint64 MirallConfigFile::forceSyncInterval(const QString& connection) const
bool MirallConfigFile::passwordStorageAllowed( const QString& connection )
{
uint pollInterval = remotePollInterval(connection);
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
quint64 interval = settings.value( QLatin1String(forceSyncIntervalC), 10 * pollInterval ).toULongLong();
if( interval < pollInterval) {
qDebug() << "Force sync interval is less than the remote poll inteval, reverting to" << pollInterval;
interval = pollInterval;
bool skipPwd = settings.value( QLatin1String("nostoredpassword"), false ).toBool();
return !skipPwd;
}
QString MirallConfigFile::ownCloudPasswd( const QString& connection ) const
{
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
QByteArray pwdba = settings.value(QLatin1String("passwd")).toByteArray();
if( !pwdba.isEmpty() ) {
return QString::fromUtf8( QByteArray::fromBase64(pwdba) );
}
return interval;
// check the password entry, cleartext from before
// read it and convert to base64, delete the cleartext entry.
QString p = settings.value(QLatin1String("password")).toString();
if( ! p.isEmpty() ) {
// its there, save base64-encoded and delete.
pwdba = p.toUtf8();
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
settings.remove( QLatin1String("password") );
settings.sync();
}
return p;
}
QString MirallConfigFile::ownCloudVersion() const
@@ -434,11 +410,11 @@ bool MirallConfigFile::ownCloudSkipUpdateCheck( const QString& connection ) cons
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
bool skipIt = settings.value( QLatin1String(skipUpdateCheckC), false ).toBool();
bool skipIt = settings.value( QLatin1String("skipUpdateCheck"), false ).toBool();
return skipIt;
}
@@ -448,27 +424,31 @@ void MirallConfigFile::setOwnCloudSkipUpdateCheck( bool skip, const QString& con
QString con( connection );
if( connection.isEmpty() ) con = defaultConnection();
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
settings.setValue( QLatin1String(skipUpdateCheckC), QVariant(skip) );
settings.setValue( QLatin1String("skipUpdateCheck"), QVariant(skip) );
settings.sync();
}
int MirallConfigFile::maxLogLines() const
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
return settings.value( QLatin1String(maxLogLinesC), DEFAULT_MAX_LOG_LINES ).toInt();
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(QLatin1String("Logging"));
int logLines = settings.value( QLatin1String("maxLogLines"), 20000 ).toInt();
return logLines;
}
void MirallConfigFile::setMaxLogLines( int lines )
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.setValue(QLatin1String(maxLogLinesC), lines);
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(QLatin1String("Logging"));
settings.setValue(QLatin1String("maxLogLines"), lines);
settings.sync();
}
@@ -495,8 +475,6 @@ void MirallConfigFile::acceptCustomConfig()
QString srcConfig = configFile(); // this considers the custom handle
credentialsPerConfig.insert(QString(), credentialsPerConfig[_customHandle]);
credentialsPerConfig.remove(_customHandle);
_customHandle.clear();
QString targetConfig = configFile();
QString targetBak = targetConfig + QLatin1String(".bak");
@@ -518,7 +496,18 @@ void MirallConfigFile::acceptCustomConfig()
}
QFile::remove( targetBak );
credentialsPerConfig[QString()]->persistForUrl(ownCloudUrl());
// inform the credential store about the password change.
QString url = ownCloudUrl();
QString user = ownCloudUser();
QString pwd = ownCloudPasswd();
bool allow = passwordStorageAllowed();
if( pwd.isEmpty() ) {
qDebug() << "Password is empty, skipping to write cred store.";
} else {
CredentialStore::instance()->setCredentials(url, user, pwd, allow);
CredentialStore::instance()->saveCredentials();
}
}
void MirallConfigFile::setProxyType(int proxyType,
@@ -527,129 +516,61 @@ void MirallConfigFile::setProxyType(int proxyType,
const QString& user,
const QString& pass)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(QLatin1String("proxy"));
settings.setValue(QLatin1String(proxyTypeC), proxyType);
settings.setValue(QLatin1String("type"), proxyType);
if (proxyType == QNetworkProxy::HttpProxy ||
proxyType == QNetworkProxy::Socks5Proxy) {
settings.setValue(QLatin1String(proxyHostC), host);
settings.setValue(QLatin1String(proxyPortC), port);
settings.setValue(QLatin1String(proxyNeedsAuthC), needsAuth);
settings.setValue(QLatin1String(proxyUserC), user);
settings.setValue(QLatin1String(proxyPassC), pass.toUtf8().toBase64());
settings.setValue(QLatin1String("host"), host);
settings.setValue(QLatin1String("port"), port);
settings.setValue(QLatin1String("needsAuth"), needsAuth);
settings.setValue(QLatin1String("user"), user);
settings.setValue(QLatin1String("pass"), pass.toUtf8().toBase64());
}
settings.sync();
}
QVariant MirallConfigFile::getValue(const QString& param, const QString& group,
const QVariant& defaultValue) const
QVariant MirallConfigFile::getValue(const QString& param, const QString& group) const
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
if (!group.isEmpty())
settings.beginGroup(group);
QSettings settings( configFile(), QSettings::IniFormat );
settings.setIniCodec( "UTF-8" );
settings.beginGroup(group);
return settings.value(param, defaultValue);
}
void MirallConfigFile::setValue(const QString& key, const QVariant &value)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.setValue(key, value);
return settings.value(param);
}
int MirallConfigFile::proxyType() const
{
return getValue(QLatin1String(proxyTypeC)).toInt();
return getValue(QLatin1String("type"), QLatin1String("proxy")).toInt();
}
QString MirallConfigFile::proxyHostName() const
{
return getValue(QLatin1String(proxyHostC)).toString();
return getValue(QLatin1String("host"), QLatin1String("proxy")).toString();
}
int MirallConfigFile::proxyPort() const
{
return getValue(QLatin1String(proxyPortC)).toInt();
return getValue(QLatin1String("port"), QLatin1String("proxy")).toInt();
}
bool MirallConfigFile::proxyNeedsAuth() const
{
return getValue(QLatin1String(proxyNeedsAuthC)).toBool();
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toBool();
}
QString MirallConfigFile::proxyUser() const
{
return getValue(QLatin1String(proxyUserC)).toString();
return getValue(QLatin1String("user"), QLatin1String("proxy")).toString();
}
QString MirallConfigFile::proxyPassword() const
{
QByteArray pass = getValue(proxyPassC).toByteArray();
QByteArray pass = getValue(QLatin1String("pass"), QLatin1String("proxy")).toByteArray();
return QString::fromUtf8(QByteArray::fromBase64(pass));
}
int MirallConfigFile::useUploadLimit() const
{
return getValue(useUploadLimitC, QString::null, -1).toInt();
}
bool MirallConfigFile::useDownloadLimit() const
{
return getValue(useDownloadLimitC, QString::null, false).toBool();
}
void MirallConfigFile::setUseUploadLimit(int val)
{
setValue(useUploadLimitC, val);
}
void MirallConfigFile::setUseDownloadLimit(bool enable)
{
setValue(useDownloadLimitC, enable);
}
int MirallConfigFile::uploadLimit() const
{
return getValue(uploadLimitC, QString::null, 10).toInt();
}
int MirallConfigFile::downloadLimit() const
{
return getValue(downloadLimitC, QString::null, 80).toInt();
}
void MirallConfigFile::setUploadLimit(int kbytes)
{
setValue(uploadLimitC, kbytes);
}
void MirallConfigFile::setDownloadLimit(int kbytes)
{
setValue(downloadLimitC, kbytes);
}
bool MirallConfigFile::monoIcons() const
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
return settings.value(QLatin1String(monoIconsC), false).toBool();
}
void MirallConfigFile::setMonoIcons(bool useMonoIcons)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setIniCodec("UTF-8");
settings.setValue(QLatin1String(monoIconsC), useMonoIcons);
}
AbstractCredentials* MirallConfigFile::getCredentials() const
{
return credentialsPerConfig[_customHandle].data();
}
}
+27 -45
Ver Arquivo
@@ -15,26 +15,33 @@
#ifndef MIRALLCONFIGFILE_H
#define MIRALLCONFIGFILE_H
#include <QSharedPointer>
#include <QString>
#include <QVariant>
class QWidget;
class QVariant;
namespace Mirall {
class AbstractCredentials;
class MirallConfigFile
{
/* let only CredentialStore read the password from the file. All other classes
* should work with CredentialStore to get the credentials. */
friend class CredentialStore;
friend class ConnectionValidator;
public:
MirallConfigFile( const QString& appendix = QString(), bool useOldConfig = false );
MirallConfigFile( const QString& appendix = QString() );
enum Scope { UserScope, SystemScope };
// enum customMediaType {
// oCSetupTop, // ownCloud connect page
// oCSetupSide,
// oCSetupBottom,
// oCSetupFixUrl,
// oCSetupResultTop // ownCloud connect result page
// };
QString configPath() const;
QString configFile() const;
QString excludeFile(Scope scope) const;
QString excludeFile() const;
bool exists();
@@ -43,13 +50,15 @@ public:
void writeOwncloudConfig( const QString& connection,
const QString& url,
AbstractCredentials* credentials);
AbstractCredentials* getCredentials() const;
const QString& user,
const QString& passwd );
void removeConnection( const QString& connection = QString() );
QString ownCloudUrl( const QString& connection = QString() ) const;
QString ownCloudUser( const QString& connection = QString() ) const;
QString ownCloudUrl( const QString& connection = QString(), bool webdav = false ) const;
void setOwnCloudUrl(const QString &connection, const QString& );
// the certs do not depend on a connection.
QByteArray caCerts();
@@ -72,17 +81,11 @@ public:
/* Set poll interval. Value in microseconds has to be larger than 5000 */
void setRemotePollInterval(int interval, const QString& connection = QString() );
/* Force sync interval, in milliseconds */
quint64 forceSyncInterval(const QString &connection = QString()) const;
// Custom Config: accept the custom config to become the main one.
void acceptCustomConfig();
// Custom Config: remove the custom config file.
void cleanupCustomConfig();
bool monoIcons() const;
void setMonoIcons(bool);
// proxy settings
void setProxyType(int proxyType,
const QString& host = QString(),
@@ -97,47 +100,26 @@ public:
QString proxyUser() const;
QString proxyPassword() const;
/** 0: no limit, 1: manual, >0: automatic */
int useUploadLimit() const;
bool useDownloadLimit() const;
void setUseUploadLimit(int);
void setUseDownloadLimit(bool);
/** in kbyte/s */
int uploadLimit() const;
int downloadLimit() const;
void setUploadLimit(int kbytes);
void setDownloadLimit(int kbytes);
static void setConfDir(const QString &value);
bool optionalDesktopNotifications() const;
void setOptionalDesktopNotifications(bool show);
QString seenVersion() const;
void setSeenVersion(const QString &version);
void saveGeometry(QWidget *w);
void restoreGeometry(QWidget *w);
protected:
void storeData(const QString& group, const QString& key, const QVariant& value);
QVariant retrieveData(const QString& group, const QString& key) const;
void removeData(const QString& group, const QString& key);
bool dataExists(const QString& group, const QString& key) const;
// these classes can only be access from CredentialStore as a friend class.
QString ownCloudPasswd( const QString& connection = QString() ) const;
void clearPasswordFromConfig( const QString& connect = QString() );
bool writePassword( const QString& passwd, const QString& connection = QString() );
private:
QVariant getValue(const QString& param, const QString& group = QString::null,
const QVariant& defaultValue = QVariant()) const;
void setValue(const QString& key, const QVariant &value);
QVariant getValue(const QString& param, const QString& group) const;
private:
typedef QSharedPointer< AbstractCredentials > SharedCreds;
static bool _askedUser;
static QString _oCVersion;
static QString _confDir;
static QMap< QString, SharedCreds > credentialsPerConfig;
QString _customHandle;
};
}
-161
Ver Arquivo
@@ -1,161 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "networksettings.h"
#include "ui_networksettings.h"
#include "mirall/theme.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/application.h"
#include "mirall/utility.h"
#include "mirall/mirallconfigfile.h"
#include <QNetworkProxy>
namespace Mirall {
NetworkSettings::NetworkSettings(QWidget *parent) :
QWidget(parent),
_ui(new Ui::NetworkSettings)
{
_ui->setupUi(this);
_ui->hostLineEdit->setPlaceholderText(tr("Hostname of proxy server"));
_ui->userLineEdit->setPlaceholderText(tr("Username for proxy server"));
_ui->passwordLineEdit->setPlaceholderText(tr("Password for proxy server"));
_ui->typeComboBox->addItem(tr("HTTP(S) proxy"), QNetworkProxy::HttpProxy);
_ui->typeComboBox->addItem(tr("SOCKS5 proxy"), QNetworkProxy::Socks5Proxy);
_ui->authRequiredcheckBox->setEnabled(true);
connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)),
_ui->manualSettings, SLOT(setEnabled(bool)));
connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)),
_ui->typeComboBox, SLOT(setEnabled(bool)));
connect(_ui->authRequiredcheckBox, SIGNAL(toggled(bool)),
_ui->authWidgets, SLOT(setEnabled(bool)));
loadProxySettings();
loadBWLimitSettings();
// proxy
connect(_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(saveProxySettings()));
connect(_ui->proxyButtonGroup, SIGNAL(buttonClicked(int)), SLOT(saveProxySettings()));
connect(_ui->hostLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
connect(_ui->userLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
connect(_ui->passwordLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
connect(_ui->portSpinBox, SIGNAL(editingFinished()), SLOT(saveProxySettings()));
connect(_ui->uploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->noUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->autoUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->downloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->noDownloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->downloadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
connect(_ui->uploadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
}
NetworkSettings::~NetworkSettings()
{
delete _ui;
}
void NetworkSettings::loadProxySettings()
{
// load current proxy settings
Mirall::MirallConfigFile cfgFile;
int type = cfgFile.proxyType();
switch (type) {
case QNetworkProxy::NoProxy:
_ui->noProxyRadioButton->setChecked(true);
break;
case QNetworkProxy::DefaultProxy:
_ui->systemProxyRadioButton->setChecked(true);
break;
case QNetworkProxy::Socks5Proxy:
case QNetworkProxy::HttpProxy:
_ui->typeComboBox->setCurrentIndex(_ui->typeComboBox->findData(type));
_ui->manualProxyRadioButton->setChecked(true);
break;
default:
break;
}
_ui->hostLineEdit->setText(cfgFile.proxyHostName());
int port = cfgFile.proxyPort();
if (port == 0)
port = 8080;
_ui->portSpinBox->setValue(port);
if (!cfgFile.proxyUser().isEmpty())
{
_ui->authRequiredcheckBox->setChecked(true);
_ui->userLineEdit->setText(cfgFile.proxyUser());
_ui->passwordLineEdit->setText(cfgFile.proxyPassword());
}
}
void NetworkSettings::loadBWLimitSettings()
{
MirallConfigFile cfgFile;
_ui->downloadLimitRadioButton->setChecked(cfgFile.useDownloadLimit());
int uploadLimit = cfgFile.useUploadLimit();
if ( uploadLimit >= 1 ) {
_ui->uploadLimitRadioButton->setChecked(true);
} else if (uploadLimit == 0){
_ui->noUploadLimitRadioButton->setChecked(true);
} else {
_ui->autoUploadLimitRadioButton->setChecked(true);
}
_ui->downloadSpinBox->setValue(cfgFile.downloadLimit());
_ui->uploadSpinBox->setValue(cfgFile.uploadLimit());
}
void NetworkSettings::saveProxySettings()
{
MirallConfigFile cfgFile;
if (_ui->noProxyRadioButton->isChecked()){
cfgFile.setProxyType(QNetworkProxy::NoProxy);
} else if (_ui->systemProxyRadioButton->isChecked()){
cfgFile.setProxyType(QNetworkProxy::DefaultProxy);
} else if (_ui->manualProxyRadioButton->isChecked()) {
int type = _ui->typeComboBox->itemData(_ui->typeComboBox->currentIndex()).toInt();
bool needsAuth = _ui->authRequiredcheckBox->isChecked();
QString user = _ui->userLineEdit->text();
QString pass = _ui->passwordLineEdit->text();
cfgFile.setProxyType(type, _ui->hostLineEdit->text(),
_ui->portSpinBox->value(), needsAuth, user, pass);
}
emit proxySettingsChanged();
}
void NetworkSettings::saveBWLimitSettings()
{
MirallConfigFile cfgFile;
cfgFile.setUseDownloadLimit(_ui->downloadLimitRadioButton->isChecked());
if (_ui->uploadLimitRadioButton->isChecked()) {
cfgFile.setUseUploadLimit(1);
} else if (_ui->noUploadLimitRadioButton->isChecked()) {
cfgFile.setUseUploadLimit(0);
} else if (_ui->autoUploadLimitRadioButton->isChecked()) {
cfgFile.setUseUploadLimit(-1);
}
cfgFile.setDownloadLimit(_ui->downloadSpinBox->value());
cfgFile.setUploadLimit(_ui->uploadSpinBox->value());
}
} // namespace Mirall
-50
Ver Arquivo
@@ -1,50 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_NETWORKSETTINGS_H
#define MIRALL_NETWORKSETTINGS_H
#include <QWidget>
namespace Mirall {
namespace Ui {
class NetworkSettings;
}
class NetworkSettings : public QWidget
{
Q_OBJECT
public:
explicit NetworkSettings(QWidget *parent = 0);
~NetworkSettings();
signals:
void proxySettingsChanged();
private slots:
void saveProxySettings();
void saveBWLimitSettings();
private:
void loadProxySettings();
void loadBWLimitSettings();
Ui::NetworkSettings *_ui;
};
} // namespace Mirall
#endif // MIRALL_NETWORKSETTINGS_H
-371
Ver Arquivo
@@ -1,371 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::NetworkSettings</class>
<widget class="QWidget" name="Mirall::NetworkSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>518</width>
<height>384</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="proxyGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Proxy Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="noProxyRadioButton">
<property name="text">
<string>No Proxy</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyButtonGroup</string>
</attribute>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="systemProxyRadioButton">
<property name="text">
<string>Use system proxy</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyButtonGroup</string>
</attribute>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="manualProxyRadioButton">
<property name="text">
<string>Specify proxy manually as</string>
</property>
<attribute name="buttonGroup">
<string notr="true">proxyButtonGroup</string>
</attribute>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="typeComboBox">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QWidget" name="manualSettings" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="rightMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="hostLabel">
<property name="text">
<string>Host</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="hostLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="portSpinBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8080</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="authRequiredcheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Proxy server requires authentication</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="authWidgets" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="userLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="passwordLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Download Bandwidth</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QRadioButton" name="downloadLimitRadioButton">
<property name="text">
<string>Limit to</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="downloadSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>80</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>KBytes/s</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>147</width>
<height>25</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="noDownloadLimitRadioButton">
<property name="text">
<string>No Limit</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Upload Bandwidth</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="noUploadLimitRadioButton">
<property name="text">
<string>No Limit</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="autoUploadLimitRadioButton">
<property name="text">
<string>Limit automatically</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="uploadLimitRadioButton">
<property name="text">
<string>Limit to</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QSpinBox" name="uploadSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>KBytes/s</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<zorder>autoUploadLimitRadioButton</zorder>
<zorder>uploadLimitRadioButton</zorder>
<zorder>noUploadLimitRadioButton</zorder>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>downloadLimitRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>downloadSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>73</x>
<y>69</y>
</hint>
<hint type="destinationlabel">
<x>131</x>
<y>78</y>
</hint>
</hints>
</connection>
<connection>
<sender>uploadLimitRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>uploadSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>322</x>
<y>101</y>
</hint>
<hint type="destinationlabel">
<x>411</x>
<y>106</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="proxyButtonGroup"/>
</buttongroups>
</ui>
+532
Ver Arquivo
@@ -0,0 +1,532 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@owncloud.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "mirall/owncloudfolder.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/owncloudinfo.h"
#include "mirall/credentialstore.h"
#include "mirall/logger.h"
#include "mirall/utility.h"
#include <csync.h>
#include <QDebug>
#include <QDir>
#include <QUrl>
#include <QMutexLocker>
#include <QThread>
#include <QStringList>
#include <QTextStream>
#include <QTimer>
#include <QNetworkProxy>
#include <QNetworkAccessManager>
#include <QNetworkProxyFactory>
#include <QMessageBox>
#include <QPushButton>
namespace Mirall {
void csyncLogCatcher(CSYNC *ctx,
int verbosity,
const char *function,
const char *buffer,
void *userdata)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
static QString replaceScheme(const QString &urlStr)
{
QUrl url( urlStr );
if( url.scheme() == QLatin1String("http") ) {
url.setScheme( QLatin1String("owncloud") );
} else {
// connect SSL!
url.setScheme( QLatin1String("ownclouds") );
}
return url.toString();
}
ownCloudFolder::ownCloudFolder(const QString &alias,
const QString &mpath,
const QString &secondPath,
QObject *parent)
: Folder(alias, mpath, secondPath, parent)
, _thread(0)
, _csync(0)
, _csyncError(false)
, _csyncUnavail(false)
{
ServerActionNotifier *notifier = new ServerActionNotifier(this);
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
connect(this, SIGNAL(syncFinished(SyncResult)), notifier, SLOT(slotSyncFinished(SyncResult)));
qDebug() << "****** ownCloud folder using watcher *******";
// The folder interval is set in the folder parent class.
QString url = replaceScheme(secondPath);
QString localpath = path();
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
qDebug() << "Unable to create csync-context!";
_csync_ctx = 0;
} else {
csync_set_log_callback( _csync_ctx, csyncLogCatcher );
csync_set_log_verbosity(_csync_ctx, 11);
MirallConfigFile cfgFile;
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
csync_enable_conflictcopys(_csync_ctx);
QString excludeList = cfgFile.excludeFile();
if( !excludeList.isEmpty() ) {
qDebug() << "==== added CSync exclude List: " << excludeList.toUtf8();
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
}
csync_set_auth_callback( _csync_ctx, getauth );
if( csync_init( _csync_ctx ) < 0 ) {
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
csync_destroy(_csync_ctx);
_csync_ctx = 0;
}
setProxy();
}
}
ownCloudFolder::~ownCloudFolder()
{
if( _thread ) {
_thread->quit();
csync_request_abort(_csync_ctx);
_thread->wait();
}
delete _csync;
// Destroy csync here.
csync_destroy(_csync_ctx);
}
void ownCloudFolder::setProxy()
{
if( _csync_ctx ) {
/* Store proxy */
MirallConfigFile cfgFile;
QUrl proxyUrl(cfgFile.ownCloudUrl());
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(proxyUrl);
// We set at least one in Application
Q_ASSERT(proxies.count() > 0);
QNetworkProxy proxy = proxies.first();
if (proxy.type() == QNetworkProxy::NoProxy) {
qDebug() << "Passing NO proxy to csync for" << cfgFile.ownCloudUrl();
} else {
qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type()
<< " to csync for" << cfgFile.ownCloudUrl();
}
int proxyPort = proxy.port();
csync_set_module_property(_csync_ctx, "proxy_type", (char*) proxyTypeToCStr(proxy.type()) );
csync_set_module_property(_csync_ctx, "proxy_host", proxy.hostName().toUtf8().data() );
csync_set_module_property(_csync_ctx, "proxy_port", &proxyPort );
csync_set_module_property(_csync_ctx, "proxy_user", proxy.user().toUtf8().data() );
csync_set_module_property(_csync_ctx, "proxy_pwd" , proxy.password().toUtf8().data() );
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
}
}
const char* ownCloudFolder::proxyTypeToCStr(QNetworkProxy::ProxyType type)
{
switch (type) {
case QNetworkProxy::NoProxy:
return "NoProxy";
case QNetworkProxy::DefaultProxy:
return "DefaultProxy";
case QNetworkProxy::Socks5Proxy:
return "Socks5Proxy";
case QNetworkProxy::HttpProxy:
return "HttpProxy";
case QNetworkProxy::HttpCachingProxy:
return "HttpCachingProxy";
case QNetworkProxy::FtpCachingProxy:
return "FtpCachingProxy";
default:
return "NoProxy";
}
}
int ownCloudFolder::getauth(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata
)
{
int re = 0;
QMutex mutex;
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
QString user = CredentialStore::instance()->user();
QString pwd = CredentialStore::instance()->password();
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
QMutexLocker locker( &mutex );
qstrncpy( buf, user.toUtf8().constData(), len );
} else if( qPrompt == QLatin1String("Enter your password:") ) {
QMutexLocker locker( &mutex );
// qDebug() << "OOO Password requested!";
qstrncpy( buf, pwd.toUtf8().constData(), len );
} else {
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
// SSL is requested. If the program came here, the SSL check was done by mirall
// It needs to be checked if the chain is still equal to the one which
// was verified by the user.
QRegExp regexp("fingerprint: ([\\w\\d:]+)");
bool certOk = false;
int pos = 0;
// This is the set of certificates which QNAM accepted, so we should accept
// them as well
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
QString neon_fingerprint = regexp.cap(1);
foreach( const QSslCertificate& c, certs ) {
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
if( verified_shasum == neon_fingerprint ) {
certOk = true;
break;
}
}
}
// certOk = false; DEBUG setting, keep disabled!
if( !certOk ) { // Problem!
qstrcpy( buf, "no" );
re = -1;
} else {
qstrcpy( buf, "yes" ); // Certificate is fine!
}
} else {
qDebug() << "Unknown prompt: <" << prompt << ">";
re = -1;
}
}
return re;
}
bool ownCloudFolder::isBusy() const
{
return ( _thread && _thread->isRunning() );
}
QString ownCloudFolder::secondPath() const
{
QString re(Folder::secondPath());
MirallConfigFile cfg;
QString ocUrl = cfg.ownCloudUrl(QString::null, true);
if (ocUrl.endsWith(QLatin1Char('/')))
ocUrl.chop(1);
// qDebug() << "**** " << ocUrl << " <-> " << re;
if( re.startsWith( ocUrl ) ) {
re.remove( ocUrl );
}
return re;
}
void ownCloudFolder::startSync()
{
startSync( QStringList() );
}
void ownCloudFolder::startSync(const QStringList &pathList)
{
if (!_csync_ctx) {
qDebug() << Q_FUNC_INFO << "_csync_ctx is empty. probably because csync_init has failed.";
// the error should already be set
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
return;
}
if (_thread && _thread->isRunning()) {
qCritical() << "* ERROR csync is still running and new sync requested.";
return;
}
if (_thread)
_thread->quit();
delete _csync;
delete _thread;
_errors.clear();
_csyncError = false;
_csyncUnavail = false;
MirallConfigFile cfgFile;
_syncResult.clearErrors();
_syncResult.setStatus( SyncResult::SyncPrepare );
emit syncStateChange();
qDebug() << "*** Start syncing";
_thread = new QThread(this);
_csync = new CSyncThread( _csync_ctx );
_csync->moveToThread(_thread);
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
connect(_csync, SIGNAL(started()), SLOT(slotCSyncStarted()), Qt::QueuedConnection);
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
//blocking connection so the message box happens in this thread, but block the csync thread.
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
_thread->start();
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
emit syncStarted();
}
void ownCloudFolder::slotCSyncStarted()
{
qDebug() << " * csync thread started";
_syncResult.setStatus(SyncResult::SyncRunning);
emit syncStateChange();
}
void ownCloudFolder::slotCSyncError(const QString& err)
{
_errors.append( err );
_csyncError = true;
}
void ownCloudFolder::slotCsyncUnavailable()
{
_csyncUnavail = true;
}
void ownCloudFolder::slotCSyncFinished()
{
qDebug() << "-> CSync Finished slot with error " << _csyncError;
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
qDebug() << " ** error Strings: " << _errors;
_syncResult.setErrorStrings( _errors );
qDebug() << " * owncloud csync thread finished with error";
} else if (_csyncUnavail) {
_syncResult.setStatus(SyncResult::Unavailable);
} else {
_syncResult.setStatus(SyncResult::Success);
}
if( _thread && _thread->isRunning() ) {
_thread->quit();
}
emit syncFinished( _syncResult );
}
void ownCloudFolder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
{
_syncResult.setSyncFileItemVector(items);
}
void ownCloudFolder::slotTerminateSync()
{
qDebug() << "folder " << alias() << " Terminating!";
MirallConfigFile cfg;
QString configDir = cfg.configPath();
qDebug() << "csync's Config Dir: " << configDir;
if( _thread && _csync ) {
csync_request_abort(_csync_ctx);
_thread->quit();
_thread->wait();
_csync->deleteLater();
delete _thread;
_csync = 0;
_thread = 0;
csync_resume(_csync_ctx);
}
if( ! configDir.isEmpty() ) {
QFile file( configDir + QLatin1String("/lock"));
if( file.exists() ) {
qDebug() << "After termination, lock file exists and gets removed.";
file.remove();
}
}
_errors.append( tr("The CSync thread terminated.") );
_csyncError = true;
qDebug() << "-> CSync Terminated!";
slotCSyncFinished();
}
void ownCloudFolder::slotLocalPathChanged( const QString& dir )
{
QDir notifiedDir(dir);
QDir localPath( path() );
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
if( !localPath.exists() ) {
qDebug() << "XXXXXXX The sync folder root was removed!!";
if( _thread && _thread->isRunning() ) {
qDebug() << "CSync currently running, set wipe flag!!";
} else {
qDebug() << "CSync not running, wipe it now!!";
wipe();
}
qDebug() << "ALARM: The local path was DELETED!";
}
}
}
// This removes the csync File database if the sync folder definition is removed
// permanentely. This is needed to provide a clean startup again in case another
// local folder is synced to the same ownCloud.
// See http://bugs.owncloud.org/thebuggenie/owncloud/issues/oc-788
void ownCloudFolder::wipe()
{
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
QFile file(stateDbFile);
if( file.exists() ) {
if( !file.remove()) {
qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile;
} else {
qDebug() << "wipe: Removed csync StateDB " << stateDbFile;
}
} else {
qDebug() << "WRN: statedb is empty, can not remove.";
}
// Check if the tmp database file also exists
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
QFile ctmpFile( ctmpName );
if( ctmpFile.exists() ) {
ctmpFile.remove();
}
}
ServerActionNotifier::ServerActionNotifier(QObject *parent)
: QObject(parent)
{
}
void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
{
SyncFileItemVector items = result.syncFileItemVector();
if (items.count() == 0)
return;
int newItems = 0;
int removedItems = 0;
int updatedItems = 0;
SyncFileItem firstItemNew;
SyncFileItem firstItemDeleted;
SyncFileItem firstItemUpdated;
foreach (const SyncFileItem &item, items) {
if (item._dir == SyncFileItem::Down) {
switch (item._instruction) {
case CSYNC_INSTRUCTION_NEW:
newItems++;
if (firstItemNew.isEmpty())
firstItemNew = item;
break;
case CSYNC_INSTRUCTION_REMOVE:
removedItems++;
if (firstItemDeleted.isEmpty())
firstItemDeleted = item;
break;
case CSYNC_INSTRUCTION_UPDATED:
updatedItems++;
if (firstItemUpdated.isEmpty())
firstItemUpdated = item;
break;
default:
// nothing.
break;
}
}
}
if (newItems > 0) {
QString file = QDir::toNativeSeparators(firstItemNew._file);
if (newItems == 1)
emit guiLog(tr("New file available"), tr("'%1' has been synced to this machine.").arg(file));
else
emit guiLog(tr("New files available"), tr("'%1' and %n other file(s) have been synced to this machine.",
"", newItems-1).arg(file));
}
if (removedItems > 0) {
QString file = QDir::toNativeSeparators(firstItemDeleted._file);
if (removedItems == 1)
emit guiLog(tr("File removed"), tr("'%1' has been removed.").arg(file));
else
emit guiLog(tr("Files removed"), tr("'%1' and %n other file(s) have been removed.",
"", removedItems-1).arg(file));
}
if (updatedItems > 0) {
QString file = QDir::toNativeSeparators(firstItemUpdated._file);
if (updatedItems == 1)
emit guiLog(tr("File updated"), tr("'%1' has been updated.").arg(file));
else
emit guiLog(tr("Files updated"), tr("'%1' and %n other file(s) have been updated.",
"", updatedItems-1).arg(file));
}
}
void ownCloudFolder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{
QString msg = direction == SyncFileItem::Down ?
tr("This sync would remove all the files in the local sync folder '%1'.\n"
"If you or your administrator have reset your account on the server, choose "
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
tr("This sync would remove all the files in the sync folder '%1'.\n"
"This might be because the folder was silently reconfigured, or that all "
"the file were manually removed.\n"
"Are you sure you want to perform this operation?");
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
msg.arg(alias()));
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;
}
*cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) {
wipe();
}
}
} // ns
+116
Ver Arquivo
@@ -0,0 +1,116 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_ownCloudFolder_H
#define MIRALL_ownCloudFolder_H
#include <QMutex>
#include <QThread>
#include <QStringList>
#include "mirall/folder.h"
#include "mirall/csyncthread.h"
class QProcess;
class QTimer;
namespace Mirall {
enum SyncFileStatus_s {
STATUS_NONE,
STATUS_EVAL,
STATUS_REMOVE,
STATUS_RENAME,
STATUS_NEW,
STATUS_CONFLICT,
STATUS_IGNORE,
STATUS_SYNC,
STATUS_STAT_ERROR,
STATUS_ERROR,
STATUS_UPDATED
};
typedef SyncFileStatus_s SyncFileStatus;
class ServerActionNotifier : public QObject
{
Q_OBJECT
public:
ServerActionNotifier(QObject *parent = 0);
public slots:
void slotSyncFinished(const SyncResult &result);
signals:
void guiLog(const QString&, const QString&);
void sendResults();
private:
};
class ownCloudFolder : public Folder
{
Q_OBJECT
public:
ownCloudFolder(const QString &alias,
const QString &path,
const QString &secondPath, QObject *parent = 0L);
virtual ~ownCloudFolder();
QString secondPath() const;
virtual bool isBusy() const;
virtual void startSync(const QStringList &pathList);
virtual void wipe();
/* get status about a singel file. */
SyncFileStatus fileStatus( const QString& );
void setProxy();
public slots:
void startSync();
void slotTerminateSync();
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
protected slots:
void slotLocalPathChanged( const QString& );
void slotThreadTreeWalkResult(const SyncFileItemVector& );
private slots:
void slotCSyncStarted();
void slotCSyncError(const QString& );
void slotCsyncUnavailable();
void slotCSyncFinished();
private:
static int getauth(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata
);
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
QString _secondPath;
QThread *_thread;
CSyncThread *_csync;
QStringList _errors;
bool _csyncError;
bool _csyncUnavail;
bool _wipeDb;
SyncFileItemVector _items;
CSYNC *_csync_ctx;
};
}
#endif
+221 -268
Ver Arquivo
@@ -15,19 +15,33 @@
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "mirall/utility.h"
#include "mirall/logger.h"
#include "creds/abstractcredentials.h"
#include <QtCore>
#include <QtGui>
#include <QAuthenticator>
#if QT46_IMPL
#include <QHttp>
#endif
#define DEFAULT_CONNECTION QLatin1String("default");
static const char WEBDAV_PATH[] = "remote.php/webdav/";
namespace Mirall
{
class oCCookieJar : public QNetworkCookieJar
{
public:
QList<QNetworkCookie> cookiesForUrl ( const QUrl & url ) const {
QList<QNetworkCookie> list;
return list;
}
};
ownCloudInfo *ownCloudInfo::_instance = 0;
ownCloudInfo* ownCloudInfo::instance()
@@ -48,16 +62,13 @@ ownCloudInfo* ownCloudInfo::instance()
ownCloudInfo::ownCloudInfo() :
QObject(0),
_manager(0),
_authAttempts(0),
_lastQuotaUsedBytes(0),
_lastQuotaTotalBytes(0)
_manager(0)
{
_connection = Theme::instance()->appName();
connect(this, SIGNAL(guiLog(QString,QString)),
Logger::instance(), SIGNAL(guiLog(QString,QString)));
// this will set credentials specific qnam
setCustomConfigHandle(QString());
setNetworkAccessManager( new QNetworkAccessManager( this ) );
}
void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam )
@@ -72,7 +83,18 @@ void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam )
connect( _manager, SIGNAL( sslErrors(QNetworkReply*, QList<QSslError>)),
this, SIGNAL(sslFailed(QNetworkReply*, QList<QSslError>)) );
// The authenticationRequired signal is not handled because the creds are set
// in the request header.
#if 0
connect( _manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*)));
#endif
// no cookie jar so far.
_manager->setCookieJar(new oCCookieJar);
_certsUntrusted = false;
}
ownCloudInfo::~ownCloudInfo()
@@ -84,8 +106,6 @@ void ownCloudInfo::setCustomConfigHandle( const QString& handle )
_configHandle = handle;
_authAttempts = 0; // allow a couple of tries again.
resetSSLUntrust();
MirallConfigFile cfg(_configHandle);
setNetworkAccessManager (cfg.getCredentials()->getQNAM());
}
bool ownCloudInfo::isConfigured()
@@ -96,32 +116,28 @@ bool ownCloudInfo::isConfigured()
QNetworkReply *ownCloudInfo::checkInstallation()
{
_redirectCount = 0;
MirallConfigFile cfgFile( _configHandle );
QUrl url ( cfgFile.ownCloudUrl( _connection ) + QLatin1String("status.php") );
/* No authentication required for this. */
return getRequest(url);
return getRequest( QLatin1String("status.php"), false );
}
QNetworkReply* ownCloudInfo::getWebDAVPath( const QString& path )
{
_redirectCount = 0;
QUrl url ( webdavUrl( _connection ) + path );
QNetworkReply *reply = getRequest(url);
_directories[reply] = path;
return reply;
return getRequest( path, true );
}
QNetworkReply* ownCloudInfo::getRequest( const QUrl& url )
QNetworkReply* ownCloudInfo::getRequest( const QString& path, bool webdav )
{
qDebug() << "Get Request to " << url;
qDebug() << "Get Request to " << path;
MirallConfigFile cfgFile( _configHandle );
QString url = cfgFile.ownCloudUrl( _connection, webdav ) + path;
QNetworkRequest request;
request.setUrl( url );
request.setUrl( QUrl( url ) );
setupHeaders( request, 0 );
QNetworkReply *reply = _manager->get( request );
connect( reply, SIGNAL(finished()), SLOT(slotReplyFinished()));
_directories[reply] = path;
if( !_configHandle.isEmpty() ) {
qDebug() << "Setting config handle " << _configHandle;
@@ -133,16 +149,87 @@ QNetworkReply* ownCloudInfo::getRequest( const QUrl& url )
return reply;
}
#if QT46_IMPL
QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
{
qDebug() << "OCInfo Making dir " << dir;
MirallConfigFile cfgFile( _configHandle );
QUrl url = QUrl( cfgFile.ownCloudUrl( _connection, true ) + dir );
QHttp::ConnectionMode conMode = QHttp::ConnectionModeHttp;
if (url.scheme() == "https")
conMode = QHttp::ConnectionModeHttps;
QHttp* qhttp = new QHttp(QString(url.encodedHost()), conMode, 0, this);
connect(qhttp, SIGNAL(requestStarted(int)), this,SLOT(qhttpRequestStarted(int)));
connect(qhttp, SIGNAL(requestFinished(int, bool)), this,SLOT(qhttpRequestFinished(int,bool)));
connect(qhttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(qhttpResponseHeaderReceived(QHttpResponseHeader)));
//connect(qhttp, SIGNAL(authenticationRequired(QString,quint16,QAuthenticator*)), this, SLOT(qhttpAuthenticationRequired(QString,quint16,QAuthenticator*)));
QHttpRequestHeader header("MKCOL", QString(url.encodedPath()), 1,1); /* header */
header.setValue("Host", QString(url.encodedHost()));
header.setValue("User-Agent", Utility::userAgentString());
header.setValue("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
header.setValue("Accept-Language", "it,de-de;q=0.8,it-it;q=0.6,en-us;q=0.4,en;q=0.2");
header.setValue("Connection", "keep-alive");
header.setContentType("application/x-www-form-urlencoded"); //important
header.setContentLength(0);
QString con = _configHandle;
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
if( _credentials.contains(con)) {
oCICredentials creds = _credentials.value(con);
QString concatenated = creds.user + QLatin1Char(':') + creds.passwd;
const QString b(QLatin1String("Basic "));
QByteArray data = b.toLocal8Bit() + concatenated.toLocal8Bit().toBase64();
header.setValue("Authorization", data);
qhttp->setUser( creds.user, creds.passwd );
}
int david = qhttp->request(header,0,0);
//////////////// connect(davinfo, SIGNAL(dataSendProgress(int,int)), this, SLOT(SendStatus(int, int)));
/////////////////connect(davinfo, SIGNAL(done(bool)), this,SLOT(DavWake(bool)));
//connect(_http, SIGNAL(requestFinished(int, bool)), this,SLOT(qhttpRequestFinished(int,bool)));
///////////connect(davinfo, SIGNAL(responseHeaderReceived(constQHttpResponseHeader &)), this, SLOT(RegisterBackHeader(constQHttpResponseHeader &)));
return NULL;
}
void ownCloudInfo::qhttpResponseHeaderReceived(const QHttpResponseHeader& header)
{
qDebug() << "Resp:" << header.toString();
if (header.statusCode() == 201)
emit webdavColCreated( QNetworkReply::NoError );
else
qDebug() << "http request failed" << header.toString();
}
void ownCloudInfo::qhttpRequestStarted(int id)
{
qDebug() << "QHttp based request started " << id;
}
void ownCloudInfo::qhttpRequestFinished(int id, bool success )
{
qDebug() << "HIT!";
QHttp* qhttp = qobject_cast<QHttp*>(sender());
if( success ) {
qDebug() << "QHttp based request successful";
} else {
qDebug() << "QHttp based request failed: " << qhttp->errorString();
}
}
#else
QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
{
qDebug() << "OCInfo Making dir " << dir;
_authAttempts = 0;
MirallConfigFile cfgFile( _configHandle );
QNetworkRequest req;
QUrl url = QUrl(webdavUrl(_connection));
url.setEncodedPath(url.encodedPath()+QUrl::toPercentEncoding(dir, "/"));
req.setUrl( url );
QNetworkReply *reply = davRequest("MKCOL", req, 0);
req.setUrl( QUrl( cfgFile.ownCloudUrl( _connection, true ) + dir ) );
QNetworkReply *reply = davRequest(QLatin1String("MKCOL"), req, 0);
// remember the confighandle used for this request
if( ! _configHandle.isEmpty() )
@@ -159,62 +246,6 @@ QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir )
return reply;
}
QNetworkReply* ownCloudInfo::getQuotaRequest( const QString& dir )
{
QNetworkRequest req;
req.setUrl( QUrl( webdavUrl(_connection) + dir ) );
req.setRawHeader("Depth", "0");
QByteArray xml("<?xml version=\"1.0\" ?>\n"
"<d:propfind xmlns:d=\"DAV:\">\n"
" <d:prop>\n"
" <d:quota-available-bytes/>\n"
" <d:quota-used-bytes/>\n"
" <d:getetag/>"
" </d:prop>\n"
"</d:propfind>\n");
QBuffer *buf = new QBuffer;
buf->setData(xml);
buf->open(QIODevice::ReadOnly);
QNetworkReply *reply = davRequest("PROPFIND", req, buf);
buf->setParent(reply);
if( reply->error() != QNetworkReply::NoError ) {
qDebug() << "getting quota: request network error: " << reply->errorString();
}
connect( reply, SIGNAL( finished()), SLOT(slotGetQuotaFinished()) );
connect( reply, SIGNAL( error(QNetworkReply::NetworkError)),
this, SLOT( slotError(QNetworkReply::NetworkError)));
return reply;
}
QNetworkReply* ownCloudInfo::getDirectoryListing( const QString& dir )
{
QNetworkRequest req;
req.setUrl( QUrl( webdavUrl(_connection) + dir ) );
req.setRawHeader("Depth", "1");
QByteArray xml("<?xml version=\"1.0\" ?>\n"
"<d:propfind xmlns:d=\"DAV:\">\n"
" <d:prop>\n"
" <d:resourcetype/>\n"
" </d:prop>\n"
"</d:propfind>\n");
QBuffer *buf = new QBuffer;
buf->setData(xml);
buf->open(QIODevice::ReadOnly);
QNetworkReply *reply = davRequest("PROPFIND", req, buf);
buf->setParent(reply);
if( reply->error() != QNetworkReply::NoError ) {
qDebug() << "getting quota: request network error: " << reply->errorString();
}
connect( reply, SIGNAL( finished()), SLOT(slotGetDirectoryListingFinished()) );
connect( reply, SIGNAL( error(QNetworkReply::NetworkError)),
this, SLOT( slotError(QNetworkReply::NetworkError)));
return reply;
}
void ownCloudInfo::slotMkdirFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
@@ -232,90 +263,47 @@ void ownCloudInfo::slotMkdirFinished()
reply->deleteLater();
}
#endif
void ownCloudInfo::slotGetQuotaFinished()
// FIXME: remove this later, once the new connection dialog has settled.
#if 0
void ownCloudInfo::slotAuthentication( QNetworkReply *reply, QAuthenticator *auth )
{
bool ok = false;
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if( !(auth && reply) ) return;
QString configHandle;
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response
QXmlStreamReader reader(reply);
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
// an empty config handle is ok for the default config.
if( _configHandleMap.contains(reply) ) {
configHandle = _configHandleMap[reply];
qDebug() << "Auth: Have a custom config handle: " << configHandle;
}
qint64 quotaUsedBytes = 0;
qint64 quotaAvailableBytes = 0;
QString etag;
qDebug() << "Auth request to me and I am " << this;
_authAttempts++;
MirallConfigFile cfgFile( configHandle );
qDebug() << "Authenticating request for " << reply->url();
if( reply->url().toString().startsWith( cfgFile.ownCloudUrl( _connection, true )) ) {
while (!reader.atEnd()) {
QXmlStreamReader::TokenType type = reader.readNext();
if (type == QXmlStreamReader::StartElement &&
reader.namespaceUri() == QLatin1String("DAV:")) {
QString name = reader.name().toString();
if (name == QLatin1String("quota-used-bytes")) {
quotaUsedBytes = reader.readElementText().toLongLong(&ok);
if (!ok) quotaUsedBytes = 0;
} else if (name == QLatin1String("quota-available-bytes")) {
quotaAvailableBytes = reader.readElementText().toLongLong(&ok);
if (!ok) quotaAvailableBytes = 0;
} else if (name == QLatin1String("getetag")) {
etag = reader.readElementText();
}
}
QString con = configHandle;
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
if( _credentials.contains(con)) {
oCICredentials creds = _credentials.value(con);
auth->setUser( creds.user );
auth->setPassword( creds.passwd );
} else {
qDebug() << "Unable to get Credentials, not set!";
reply->close();
}
qint64 total = quotaUsedBytes + quotaAvailableBytes;
_lastQuotaTotalBytes = total;
_lastQuotaUsedBytes = quotaUsedBytes;
emit quotaUpdated(total, quotaUsedBytes);
_lastEtag = etag;
} else {
_lastQuotaTotalBytes = 0;
_lastQuotaUsedBytes = 0;
qDebug() << "WRN: attempt to authenticate to different url - attempt " <<_authAttempts;
}
reply->deleteLater();
}
void ownCloudInfo::slotGetDirectoryListingFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response
QXmlStreamReader reader(reply);
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
QStringList folders;
QString currentItem;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType type = reader.readNext();
if (type == QXmlStreamReader::StartElement &&
reader.namespaceUri() == QLatin1String("DAV:")) {
QString name = reader.name().toString();
if (name == QLatin1String("href")) {
currentItem = reader.readElementText();
} else if (name == QLatin1String("collection") &&
!currentItem.isEmpty()) {
folders.append(QUrl::fromEncoded(currentItem.toLatin1()).path());
currentItem.clear();
}
}
}
emit directoryListingUpdated(folders);
if( _authAttempts > 1) {
qDebug() << "Too many attempts to authenticate. Stop request.";
reply->close();
}
reply->deleteLater();
}
QList<QNetworkCookie> ownCloudInfo::getLastAuthCookies()
{
QUrl url = QUrl( webdavUrl(_connection));
QList<QNetworkCookie> cookies = _manager->cookieJar()->cookiesForUrl(url);
return cookies;
}
#endif
QString ownCloudInfo::configHandle(QNetworkReply *reply)
{
@@ -332,6 +320,20 @@ QList<QSslCertificate> ownCloudInfo::certificateChain() const
return _certificateChain;
}
QUrl ownCloudInfo::redirectUrl(const QUrl& possibleRedirectUrl,
const QUrl& oldRedirectUrl) const {
QUrl redirectUrl;
/*
* Check if the URL is empty and
* that we aren't being fooled into a infinite redirect loop.
*/
if(!possibleRedirectUrl.isEmpty() &&
possibleRedirectUrl != oldRedirectUrl) {
redirectUrl = possibleRedirectUrl;
}
return redirectUrl;
}
//
// There have been problems with the finish-signal coming from the networkmanager.
// To avoid that, the reply-signals were connected and the data is taken from the
@@ -352,17 +354,12 @@ void ownCloudInfo::slotReplyFinished()
}
// Detect redirect url
QUrl possibleRedirUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QVariant possibleRedirUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
/* We'll deduct if the redirection is valid in the redirectUrl function */
_urlRedirectedTo = redirectUrl( possibleRedirUrl.toUrl(),
_urlRedirectedTo );
if (!possibleRedirUrl.isEmpty() && _redirectCount++ > 10) {
// Are we in a redirect loop
qDebug() << "Redirect loop while redirecting to" << possibleRedirUrl;
possibleRedirUrl.clear();
}
if(!possibleRedirUrl.isEmpty()) {
if(!_urlRedirectedTo.isEmpty()) {
QString configHandle;
qDebug() << "Redirected to " << possibleRedirUrl;
@@ -375,28 +372,24 @@ void ownCloudInfo::slotReplyFinished()
}
QString path = _directories[reply];
if (path.isEmpty()) {
path = QLatin1String("status.php");
} else {
path.prepend( QLatin1String(WEBDAV_PATH) );
}
qDebug() << "This path was redirected: " << path;
QString newUrl = possibleRedirUrl.toString();
if( !path.isEmpty() && newUrl.endsWith( path )) {
MirallConfigFile cfgFile( configHandle );
QString newUrl = _urlRedirectedTo.toString();
if( newUrl.endsWith( path )) {
// cut off the trailing path
newUrl.chop( path.length() );
_urlRedirectedTo = newUrl;
qDebug() << "Updated url to" << newUrl;
getRequest( possibleRedirUrl );
cfgFile.setOwnCloudUrl( _connection, newUrl );
qDebug() << "Update the config file url to " << newUrl;
getRequest( path, false ); // FIXME: Redirect for webdav!
reply->deleteLater();
return;
} else {
qDebug() << "WRN: Path is not part of the redirect URL. NO redirect.";
}
reply->deleteLater();
_directories.remove(reply);
_configHandleMap.remove(reply);
return;
}
_urlRedirectedTo.clear();
// TODO: check if this is always the correct encoding
const QString version = QString::fromUtf8( reply->readAll() );
@@ -446,8 +439,8 @@ void ownCloudInfo::slotReplyFinished()
// get version out
edition = val;
} else if(key == QLatin1String("installed")) {
// Silently ignoring "installed = true" information
} else {
// Silently ignoring "installed = true" information
} else {
qDebug() << "Unknown info from ownCloud status.php: "<< key << "=" << val;
}
}
@@ -462,13 +455,15 @@ void ownCloudInfo::slotReplyFinished()
QString dir(QLatin1String("unknown"));
if( _directories.contains(reply) ) {
dir = _directories[reply];
_directories.remove(reply);
}
emit ownCloudDirExists( dir, reply );
}
if( _configHandleMap.contains(reply)) {
_configHandleMap.remove(reply);
}
reply->deleteLater();
_directories.remove(reply);
_configHandleMap.remove(reply);
}
void ownCloudInfo::resetSSLUntrust()
@@ -523,11 +518,43 @@ void ownCloudInfo::slotError( QNetworkReply::NetworkError err)
}
}
void ownCloudInfo::setCredentials( const QString& user, const QString& passwd,
const QString& configHandle )
{
QString con( configHandle );
if( configHandle.isEmpty() )
con = DEFAULT_CONNECTION;
if( _credentials.contains(con) ) {
qDebug() << "Overwriting credentials for connection " << con;
}
oCICredentials creds;
creds.user = user;
creds.passwd = passwd;
creds.connection = con;
_credentials[con] = creds;
}
// ============================================================================
void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size )
{
QUrl url( req.url() );
MirallConfigFile cfgFile(_configHandle );
QUrl url( cfgFile.ownCloudUrl( QString::null, false ) );
qDebug() << "Setting up host header: " << url.host();
req.setRawHeader( QByteArray("Host"), url.host().toUtf8() );
req.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString());
QString con = _configHandle;
if( con.isEmpty() ) con = DEFAULT_CONNECTION;
if( _credentials.contains(con)) {
oCICredentials creds = _credentials.value(con);
QString concatenated = creds.user + QLatin1Char(':') + creds.passwd;
const QString b(QLatin1String("Basic "));
QByteArray data = b.toUtf8() + concatenated.toUtf8().toBase64();
req.setRawHeader( QByteArray("Authorization"), data );
}
if (size) {
req.setHeader( QNetworkRequest::ContentLengthHeader, size);
@@ -535,92 +562,18 @@ void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size )
}
}
QNetworkReply* ownCloudInfo::davRequest(const QByteArray& reqVerb, QNetworkRequest& req, QIODevice *data)
#if QT46_IMPL
#else
QNetworkReply* ownCloudInfo::davRequest(const QString& reqVerb, QNetworkRequest& req, QByteArray *data)
{
setupHeaders(req, quint64(data ? data->size() : 0));
return _manager->sendCustomRequest(req, reqVerb, data );
}
QString ownCloudInfo::webdavUrl(const QString &connection)
{
QString url;
if (!_urlRedirectedTo.isEmpty()) {
url = _urlRedirectedTo.toString();
if( data ) {
QBuffer iobuf( data );
return _manager->sendCustomRequest(req, reqVerb.toUtf8(), &iobuf );
} else {
MirallConfigFile cfgFile(_configHandle );
url = cfgFile.ownCloudUrl( connection );
return _manager->sendCustomRequest(req, reqVerb.toUtf8(), 0 );
}
url.append( QLatin1String( WEBDAV_PATH ) );
if (!url.endsWith('/')) url.append('/');
return url;
}
#endif
}
RequestEtagJob::RequestEtagJob(const QString& dir, QObject* parent)
: QObject(parent)
{
QNetworkRequest req;
req.setUrl( QUrl( ownCloudInfo::instance()->webdavUrl(ownCloudInfo::instance()->_connection) + dir ) );
if (dir.isEmpty() || dir == "/") {
/* For the root directory, we need to query the etags of all the sub directories
* because, at the time I am writing this comment (Owncloud 5.0.9), the etag of the
* root directory is not updated when the sub directories changes */
req.setRawHeader("Depth", "1");
} else {
req.setRawHeader("Depth", "0");
}
QByteArray xml("<?xml version=\"1.0\" ?>\n"
"<d:propfind xmlns:d=\"DAV:\">\n"
" <d:prop>\n"
" <d:getetag/>"
" </d:prop>\n"
"</d:propfind>\n");
QBuffer *buf = new QBuffer;
buf->setData(xml);
buf->open(QIODevice::ReadOnly);
_reply = ownCloudInfo::instance()->davRequest("PROPFIND", req, buf);
buf->setParent(_reply);
if( _reply->error() != QNetworkReply::NoError ) {
qDebug() << "getting etag: request network error: " << _reply->errorString();
}
connect( _reply, SIGNAL( finished()), SLOT(slotFinished()) );
connect( _reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError()));
connect( _reply, SIGNAL(error(QNetworkReply::NetworkError)),
ownCloudInfo::instance(), SLOT(slotError(QNetworkReply::NetworkError)));
}
void RequestEtagJob::slotFinished()
{
if (_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response
QXmlStreamReader reader(_reply);
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
QString etag;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType type = reader.readNext();
if (type == QXmlStreamReader::StartElement &&
reader.namespaceUri() == QLatin1String("DAV:")) {
QString name = reader.name().toString();
if (name == QLatin1String("getetag")) {
etag += reader.readElementText();
}
}
}
emit etagRetreived(etag);
}
_reply->deleteLater();
deleteLater();
}
void RequestEtagJob::slotError()
{
qDebug() << "RequestEtagJob Error: " << _reply->errorString();
_reply->deleteLater();
deleteLater();
emit networkError();
}
} // ns Mirall
+37 -55
Ver Arquivo
@@ -18,9 +18,21 @@
#include <QObject>
#include <QtNetwork>
#if QT_VERSION >= 0x040700
#define QT46_IMPL 0
#else
#define QT46_IMPL 1
#endif
namespace Mirall
{
typedef struct {
QString user;
QString passwd;
QString connection;
} oCICredentials;
class ownCloudInfo : public QObject
{
Q_OBJECT
@@ -35,6 +47,12 @@ public:
*/
QNetworkReply* checkInstallation();
/**
* a general GET request to the ownCloud. If the second bool parameter is
* true, the WebDAV server is queried.
*/
QNetworkReply* getRequest( const QString&, bool );
/**
* convenience: GET request to the WebDAV server.
*/
@@ -69,16 +87,6 @@ public:
*/
QNetworkReply* mkdirRequest( const QString& );
/**
* Retrieve quota for a path. Provide a relative path.
*/
QNetworkReply* getQuotaRequest( const QString& );
/**
* provide collections in a directory via owncloud. Provide a relative path.
*/
QNetworkReply* getDirectoryListing( const QString& dir );
/**
* Use a custom ownCloud configuration file identified by handle
*/
@@ -96,17 +104,11 @@ public:
QList<QSslCertificate> certificateChain() const;
/**
* returns the owncloud webdav url.
* It may be different from the one in the config if there was a HTTP redirection
* The returned URL is guaranteed to end in a forward slash ('/')
* Store credentials for a given connection. Empty connection parameter
* means "default connection".
*/
QString webdavUrl(const QString& connection = QString());
qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; }
qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; }
QString lastEtag() const { return _lastEtag; }
QList<QNetworkCookie> getLastAuthCookies();
void setCredentials( const QString&, const QString&,
const QString& configHandle = QString::null );
signals:
// result signal with url- and version string.
@@ -117,29 +119,34 @@ signals:
void webdavColCreated( QNetworkReply::NetworkError );
void sslFailed( QNetworkReply *reply, QList<QSslError> errors );
void guiLog( const QString& title, const QString& content );
void quotaUpdated( qint64 total, qint64 quotaUsedBytes );
void directoryListingUpdated(const QStringList &directories);
public slots:
protected slots:
void slotReplyFinished( );
void slotError( QNetworkReply::NetworkError );
// void slotAuthentication( QNetworkReply*, QAuthenticator *);
#if QT46_IMPL
void qhttpRequestFinished(int id, bool success );
void qhttpRequestStarted(int id);
void qhttpResponseHeaderReceived(const QHttpResponseHeader& header);
// void qhttpAuthenticationRequired(const QString& hostname, quint16 port ,QAuthenticator* authenticator);
#else
void slotMkdirFinished();
void slotGetQuotaFinished();
void slotGetDirectoryListingFinished();
#endif
private:
explicit ownCloudInfo();
/**
* a general GET request to the ownCloud WebDAV.
*/
QNetworkReply* getRequest( const QUrl &url);
QNetworkReply* davRequest(const QByteArray&, QNetworkRequest&, QIODevice* );
QUrl redirectUrl(const QUrl&, const QUrl& ) const;
~ownCloudInfo();
void setupHeaders(QNetworkRequest &req, quint64 size );
#if QT46_IMPL
#else
QNetworkReply* davRequest(const QString&, QNetworkRequest&, QByteArray* );
#endif
static ownCloudInfo *_instance;
@@ -152,35 +159,10 @@ private:
QList<QSslCertificate> _certificateChain;
bool _certsUntrusted;
int _authAttempts;
QMap<QString, oCICredentials> _credentials;
QMutex _certChainMutex;
int _redirectCount;
qint64 _lastQuotaUsedBytes;
qint64 _lastQuotaTotalBytes;
QString _lastEtag;
friend class RequestEtagJob;
};
class RequestEtagJob : public QObject {
Q_OBJECT
QNetworkReply *_reply;
public:
explicit RequestEtagJob(const QString &dir , QObject* parent = 0);
private slots:
void slotFinished();
void slotError();
signals:
void etagRetreived(const QString &etag);
void networkError();
};
} // ns Mirall
#endif // OWNCLOUDINFO_H
+189 -288
Ver Arquivo
@@ -1,6 +1,5 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,47 +12,39 @@
* for more details.
*/
#include <QAbstractButton>
#include <QtCore>
#include <QProcess>
#include <QMessageBox>
#include <QDesktopServices>
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudwizard.h"
#include "mirall/owncloudsetupwizard.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/owncloudinfo.h"
#include "mirall/folderman.h"
#include "mirall/credentialstore.h"
#include "mirall/utility.h"
#include "mirall/mirallaccessmanager.h"
#include "creds/abstractcredentials.h"
#include "creds/dummycredentials.h"
namespace Mirall {
OwncloudSetupWizard::OwncloudSetupWizard(QObject* parent) :
class Theme;
OwncloudSetupWizard::OwncloudSetupWizard( FolderMan *folderMan, Theme *theme, QObject *parent ) :
QObject( parent ),
_ocWizard(new OwncloudWizard),
_mkdirRequestReply(),
_checkInstallationRequest(),
_checkRemoteFolderRequest(),
_configHandle(),
_remoteFolder()
_mkdirRequestReply(0),
_checkInstallationRequest(0),
_folderMan(folderMan)
{
connect( _ocWizard, SIGNAL(determineAuthType(const QString&)),
this, SLOT(slotDetermineAuthType(const QString&)));
_ocWizard = new OwncloudWizard();
connect( _ocWizard, SIGNAL(connectToOCUrl( const QString& ) ),
this, SLOT(slotConnectToOCUrl( const QString& )));
connect( _ocWizard, SIGNAL(createLocalAndRemoteFolders(QString, QString)),
this, SLOT(slotCreateLocalAndRemoteFolders(QString, QString)));
/* basicSetupFinished might be called from a reply from the network.
slotAssistantFinished might destroy the temporary QNetworkAccessManager.
Therefore Qt::QueuedConnection is required */
connect( _ocWizard, SIGNAL(basicSetupFinished(int)),
this, SLOT(slotAssistantFinished(int)), Qt::QueuedConnection);
connect( _ocWizard, SIGNAL(finished(int)),this,SLOT(slotAssistantFinished(int)));
connect( _ocWizard, SIGNAL(clearPendingRequests()),
this, SLOT(slotClearPendingRequests()));
_ocWizard->setWindowTitle( tr("%1 Connection Wizard").arg( theme->appNameGUI() ) );
}
OwncloudSetupWizard::~OwncloudSetupWizard()
@@ -61,12 +52,8 @@ OwncloudSetupWizard::~OwncloudSetupWizard()
_ocWizard->deleteLater();
}
void OwncloudSetupWizard::runWizard(QObject* obj, const char* amember, QWidget *parent)
{
OwncloudSetupWizard *wiz = new OwncloudSetupWizard(parent);
connect( wiz, SIGNAL(ownCloudWizardDone(int)), obj, amember);
FolderMan::instance()->setSyncEnabled(false);
wiz->startWizard();
OwncloudWizard *OwncloudSetupWizard::wizard() {
return _ocWizard;
}
void OwncloudSetupWizard::startWizard()
@@ -75,10 +62,14 @@ void OwncloudSetupWizard::startWizard()
MirallConfigFile cfgFile;
// Fill the entry fields with existing values.
QString url = cfgFile.ownCloudUrl();
//QString user = cfgFile.ownCloudUser();
bool configExists = !( url.isEmpty()/* || user.isEmpty()*/ );
QString user = cfgFile.ownCloudUser();
bool configExists = !( url.isEmpty() || user.isEmpty() );
_ocWizard->setConfigExists( configExists );
if( !user.isEmpty() ) {
_ocWizard->setOCUser( user );
}
if( !url.isEmpty() ) {
_ocWizard->setOCUrl( url );
}
@@ -89,30 +80,133 @@ void OwncloudSetupWizard::startWizard()
QString localFolder = Theme::instance()->defaultClientFolder();
// if its a relative path, prepend with users home dir, otherwise use as absolute path
if( !QDir(localFolder).isAbsolute() ) {
localFolder = QDir::homePath() + QDir::separator() + localFolder;
if( !localFolder.startsWith(QLatin1Char('/')) ) {
localFolder = QDir::homePath() + QDir::separator() + Theme::instance()->defaultClientFolder();
}
_ocWizard->setProperty("localFolder", localFolder);
_ocWizard->setRemoteFolder(_remoteFolder);
_ocWizard->setStartId(WizardCommon::Page_ServerSetup);
_ocWizard->setStartId(OwncloudWizard::Page_oCSetup);
_ocWizard->restart();
// settings re-initialized in initPage must be set here after restart
_ocWizard->setMultipleFoldersExist(FolderMan::instance()->map().count() > 1);
_ocWizard->setMultipleFoldersExist(_folderMan->map().count() > 1);
_ocWizard->open();
_ocWizard->show();
_ocWizard->raise();
}
void OwncloudSetupWizard::slotDetermineAuthType(const QString& serverUrl)
// Method executed when the user ends the wizard, either with 'accept' or 'reject'.
// accept the custom config to be the main one if Accepted.
void OwncloudSetupWizard::slotAssistantFinished( int result )
{
MirallConfigFile cfg( _configHandle );
if( result == QDialog::Rejected ) {
// the old config remains valid. Remove the temporary one.
cfg.cleanupCustomConfig();
qDebug() << "Rejected the new config, use the old!";
} else if( result == QDialog::Accepted ) {
qDebug() << "Config Changes were accepted!";
// go through all folders and remove the journals if the server changed.
MirallConfigFile prevCfg;
QUrl prevUrl( prevCfg.ownCloudUrl() );
QUrl newUrl( cfg.ownCloudUrl() );
bool urlHasChanged = (prevUrl.host() != newUrl.host() || prevUrl.path() != newUrl.path());
// if the user changed, its also a changed url.
if( prevCfg.ownCloudUser() != cfg.ownCloudUser() ) {
urlHasChanged = true;
qDebug() << "The User has changed, same as url change.";
}
const QString localFolder = _ocWizard->localFolder();
bool acceptCfg = true;
if( urlHasChanged ) {
_folderMan->unloadAllFolders();
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
if( startFromScratch ) {
// first try to rename (backup) the current local dir.
bool renameOk = false;
while( !renameOk ) {
renameOk = _folderMan->startFromScratch(localFolder);
if( ! renameOk ) {
QMessageBox::StandardButton but;
but = QMessageBox::question( 0, tr("Folder rename failed"),
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
if( but == QMessageBox::Abort ) {
renameOk = true;
acceptCfg = false;
}
}
}
}
}
// save the user credentials and afterwards clear the cred store.
if( acceptCfg ) {
cfg.acceptCustomConfig();
}
// Now write the resulting folder definition if folder names are set.
if( acceptCfg && urlHasChanged ) {
_folderMan->removeAllFolderDefinitions();
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
localFolder, _remoteFolder, false );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
} else {
// url is unchanged. Only the password was changed.
if( acceptCfg ) {
qDebug() << "Only password was changed, no changes to folder configuration.";
} else {
qDebug() << "User interrupted change of configuration.";
}
}
}
// clear the custom config handle
_configHandle.clear();
ownCloudInfo::instance()->setCustomConfigHandle( QString::null );
// notify others.
emit ownCloudWizardDone( result );
}
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
{
qDebug() << "Connect to url: " << url;
_ocWizard->setField(QLatin1String("OCUrl"), url );
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
.arg( Theme::instance()->appNameGUI() ).arg(url) );
testOwnCloudConnect();
}
void OwncloudSetupWizard::slotClearPendingRequests()
{
qDebug() << "Pending request: " << _mkdirRequestReply;
if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) {
qDebug() << "ABORTing pending mkdir request.";
_mkdirRequestReply->abort();
}
if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) {
qDebug() << "ABORTing pending check installation request.";
_checkInstallationRequest->abort();
}
if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) {
qDebug() << "ABORTing pending remote folder check request.";
_checkRemoteFolderRequest->abort();
}
}
void OwncloudSetupWizard::testOwnCloudConnect()
{
QString url(serverUrl);
qDebug() << "Connect to url: " << url;
_ocWizard->setField(QLatin1String("OCUrl"), url );
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 to determine authentication type...")
.arg( Theme::instance()->appNameGUI() ).arg(url) );
// write a temporary config.
QDateTime now = QDateTime::currentDateTime();
@@ -125,7 +219,8 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString& serverUrl)
_configHandle = now.toString(QLatin1String("MMddyyhhmmss"));
MirallConfigFile cfgFile( _configHandle, true );
MirallConfigFile cfgFile( _configHandle );
QString url = _ocWizard->field(QLatin1String("OCUrl")).toString();
if( url.isEmpty() ) return;
if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) {
qDebug() << "url does not start with a valid protocol, assuming https.";
@@ -135,87 +230,50 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString& serverUrl)
}
cfgFile.writeOwncloudConfig( Theme::instance()->appName(),
url,
new DummyCredentials);
_ocWizard->field(QLatin1String("OCUser")).toString(),
_ocWizard->field(QLatin1String("OCPasswd")).toString() );
// If there is already a config, take its proxy config.
if( ownCloudInfo::instance()->isConfigured() ) {
MirallConfigFile prevCfg;
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
}
// now start ownCloudInfo to check the connection.
ownCloudInfo* info = ownCloudInfo::instance();
info->setCustomConfigHandle( _configHandle );
if( info->isConfigured() ) {
// reset the SSL Untrust flag to let the SSL dialog appear again.
info->resetSSLUntrust();
connect(info, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString)));
SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
connect(info, SIGNAL(noOwncloudFound(QNetworkReply*)),
SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*)));
SLOT(slotNoOwnCloudFound(QNetworkReply*)));
_checkInstallationRequest = info->checkInstallation();
} else {
qDebug() << " ownCloud seems not to be configured, can not start test connect.";
}
}
void OwncloudSetupWizard::slotOwnCloudFoundAuth( const QString& url, const QString& infoString, const QString& version, const QString& )
void OwncloudSetupWizard::slotOwnCloudFound( const QString& url, const QString& infoString, const QString& version, const QString& )
{
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
this, SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString)));
this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*)));
this, SLOT(slotNoOwnCloudFound(QNetworkReply*)));
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>")
.arg( url ).arg(Theme::instance()->appNameGUI()).arg(infoString).arg(version));
MirallAccessManager* nm = new MirallAccessManager(this);
// TODO: We should get this path from owncloud info.
QNetworkReply* reply = nm->get (QNetworkRequest (url + "/remote.php/webdav/"));
// enable the finish button.
_ocWizard->button( QWizard::FinishButton )->setEnabled( true );
connect (reply, SIGNAL(finished()),
this, SLOT(slotAuthCheckReplyFinished()));
nm->setProperty ("mirallRedirs", QVariant (0));
// start the local folder creation
setupLocalSyncFolder();
}
void OwncloudSetupWizard::slotAuthCheckReplyFinished()
{
QNetworkReply* reply = qobject_cast< QNetworkReply* > (sender ());
QUrl redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QNetworkAccessManager* nm = reply->manager ();
const int redirCount = nm->property ("mirallRedirs").toInt();
if (redirCount > 10) {
redirection.clear ();
}
disconnect (reply, SIGNAL(finished()),
this, SLOT(slotAuthCheckReplyFinished()));
if ((reply->error () == QNetworkReply::AuthenticationRequiredError) || redirection.isEmpty()) {
reply->deleteLater();
nm->deleteLater();
_ocWizard->setAuthType (WizardCommon::HttpCreds);
} else if (redirection.toString().endsWith ("/remote.php/webdav/")) {
QNetworkReply* newReply = nm->get (QNetworkRequest(redirection));
connect (newReply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotAuthCheckReplyError(QNetworkReply::NetworkError)));
connect (newReply, SIGNAL(finished()),
this, SLOT(slotAuthCheckReplyFinished(QNetworkReply::NetworkError)));
reply->deleteLater();
nm->setProperty ("mirallRedirs", QVariant(redirCount + 1));
} else {
QRegExp shibbolethyWords ("SAML|wayf");
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
if (redirection.toString ().contains (shibbolethyWords)) {
_ocWizard->setAuthType(WizardCommon::Shibboleth);
} else {
// TODO: Send an error.
// eh?
_ocWizard->setAuthType (WizardCommon::HttpCreds);
}
reply->deleteLater();
nm->deleteLater();
}
}
void OwncloudSetupWizard::slotNoOwnCloudFoundAuth( QNetworkReply *err )
void OwncloudSetupWizard::slotNoOwnCloudFound( QNetworkReply *err )
{
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
@@ -228,81 +286,19 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth( QNetworkReply *err )
// remove the config file again
MirallConfigFile cfgFile( _configHandle );
cfgFile.cleanupCustomConfig();
finalizeSetup( false );
}
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
void OwncloudSetupWizard::setupLocalSyncFolder()
{
qDebug() << "Connect to url: " << url;
_ocWizard->setField(QLatin1String("OCUrl"), url );
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
.arg( Theme::instance()->appNameGUI() ).arg(url) );
testOwnCloudConnect();
}
if( ! _folderMan ) return;
void OwncloudSetupWizard::testOwnCloudConnect()
{
// write a temporary config.
QDateTime now = QDateTime::currentDateTime();
if( _configHandle.isEmpty() ) {
_configHandle = now.toString(QLatin1String("MMddyyhhmmss"));
}
MirallConfigFile cfgFile( _configHandle, true );
QString url = _ocWizard->field(QLatin1String("OCUrl")).toString();
if( url.isEmpty() ) return;
if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) {
qDebug() << "url does not start with a valid protocol, assuming https.";
url.prepend(QLatin1String("https://"));
// FIXME: give a hint about the auto completion
_ocWizard->setOCUrl(url);
}
cfgFile.writeOwncloudConfig( Theme::instance()->appName(),
url,
_ocWizard->getCredentials());
ownCloudInfo* info(ownCloudInfo::instance());
info->setCustomConfigHandle( _configHandle );
// If there is already a config, take its proxy config.
if( info->isConfigured() ) {
MirallConfigFile prevCfg;
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
}
connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this,SLOT(slotConnectionCheck(QString,QNetworkReply*)));
qDebug() << "# checking for authentication settings.";
_checkRemoteFolderRequest = info->getWebDAVPath(_remoteFolder ); // this call needs to be authenticated.
// continue in slotConnectionCheck
}
void OwncloudSetupWizard::slotConnectionCheck(const QString&, QNetworkReply* reply)
{
// disconnect from ownCloud Info signals
disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this, SLOT(slotConnectionCheck(QString,QNetworkReply*)));
switch (reply->error()) {
case QNetworkReply::NoError:
case QNetworkReply::ContentNotFoundError:
_ocWizard->successfulStep();
break;
default:
_ocWizard->displayError(tr("Error: Wrong credentials."));
break;
}
}
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
{
const QString localFolder = _ocWizard->property("localFolder").toString();
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
const QDir fi( localFolder );
QDir fi( localFolder );
// FIXME: Show problems with local folder properly.
bool localFolderOk = true;
bool localFolderOk = true;
if( fi.exists() ) {
// there is an existing local folder. If its non empty, it can only be synced if the
// ownCloud is newly created.
@@ -323,19 +319,18 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
}
if( localFolderOk ) {
checkRemoteFolder(remoteFolder);
checkRemoteFolder();
}
}
void OwncloudSetupWizard::checkRemoteFolder(const QString& remoteFolder)
void OwncloudSetupWizard::checkRemoteFolder()
{
ownCloudInfo* info(ownCloudInfo::instance());
connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
connect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this,SLOT(slotAuthCheckReply(QString,QNetworkReply*)));
qDebug() << "# checking for existence of remote folder.";
info->setCustomConfigHandle(_configHandle);
_checkRemoteFolderRequest = info->getWebDAVPath(remoteFolder); // this call needs to be authenticated.
qDebug() << "# checking for authentication settings.";
ownCloudInfo::instance()->setCustomConfigHandle(_configHandle);
_checkRemoteFolderRequest = ownCloudInfo::instance()->getRequest(_remoteFolder, true ); // this call needs to be authenticated.
// continue in slotAuthCheckReply
}
@@ -351,12 +346,22 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep
if( errId == QNetworkReply::NoError ) {
qDebug() << "******** Remote folder found, all cool!";
} else if( errId == QNetworkReply::AuthenticationRequiredError ) { // returned if the user is wrong.
qDebug() << "******** Password is wrong!";
error = tr("The given credentials do not authenticate.");
ok = false;
} else if( errId == QNetworkReply::OperationCanceledError ) {
// the username was wrong and ownCloudInfo was closing the request after a couple of auth tries.
qDebug() << "******** Username or password is wrong!";
error = tr("Username or password is wrong!");
ok = false;
} else if( errId == QNetworkReply::ContentNotFoundError ) {
if( createRemoteFolder() ) {
return; // Finish here, the mkdir request will go on.
} else {
// FIXME try to create the remote folder!
if( !createRemoteFolder() ) {
error = tr("The remote folder could not be accessed!");
ok = false;
} else {
return; // Finish here, the mkdir request will go on.
}
} else {
error = tr("Error: %1").arg(reply->errorString());
@@ -365,6 +370,8 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep
if( !ok ) {
_ocWizard->displayError(error);
} else {
_ocWizard->setRemoteFolder( _remoteFolder );
}
finalizeSetup( ok );
@@ -375,11 +382,10 @@ bool OwncloudSetupWizard::createRemoteFolder()
if( _remoteFolder.isEmpty() ) return false;
_ocWizard->appendToConfigurationLog( tr("creating folder on ownCloud: %1" ).arg( _remoteFolder ));
ownCloudInfo* info(ownCloudInfo::instance());
connect(info, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
connect(ownCloudInfo::instance(), SIGNAL(webdavColCreated(QNetworkReply::NetworkError)),
this, SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError)));
_mkdirRequestReply = info->mkdirRequest( _remoteFolder );
_mkdirRequestReply = ownCloudInfo::instance()->mkdirRequest( _remoteFolder );
return (_mkdirRequestReply != NULL);
}
@@ -434,118 +440,13 @@ void OwncloudSetupWizard::finalizeSetup( bool success )
+ tr("Successfully connected to %1!")
.arg(Theme::instance()->appNameGUI())
+ QLatin1String("</b></font></p>"));
_ocWizard->successfulStep();
} else {
_ocWizard->appendToConfigurationLog(QLatin1String("<p><font color=\"red\">")
+ tr("Connection to %1 could not be established. Please check again.")
.arg(Theme::instance()->appNameGUI())
+ QLatin1String("</font></p>"));
}
_ocWizard->successfullyConnected(success);
}
// Method executed when the user ends the wizard, either with 'accept' or 'reject'.
// accept the custom config to be the main one if Accepted.
void OwncloudSetupWizard::slotAssistantFinished( int result )
{
MirallConfigFile cfg( _configHandle );
FolderMan *folderMan = FolderMan::instance();
if( result == QDialog::Rejected ) {
// the old config remains valid. Remove the temporary one.
cfg.cleanupCustomConfig();
qDebug() << "Rejected the new config, use the old!";
} else if( result == QDialog::Accepted ) {
AbstractCredentials* credentials(_ocWizard->getCredentials());
qDebug() << "Config Changes were accepted!";
// go through all folders and remove the journals if the server changed.
MirallConfigFile prevCfg;
QUrl prevUrl( prevCfg.ownCloudUrl() );
QUrl newUrl( cfg.ownCloudUrl() );
AbstractCredentials* oldCredentials(prevCfg.getCredentials());
bool urlHasChanged = (prevUrl.host() != newUrl.host() ||
prevUrl.port() != newUrl.port() ||
prevUrl.path() != newUrl.path());
// if the user changed, its also a changed url.
if(credentials->changed(oldCredentials)) {
urlHasChanged = true;
qDebug() << "The User has changed, same as url change.";
}
const QString localFolder = _ocWizard->localFolder();
bool acceptCfg = true;
if( urlHasChanged ) {
// first terminate sync jobs.
folderMan->terminateSyncProcess();
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
if( startFromScratch ) {
// first try to rename (backup) the current local dir.
bool renameOk = false;
while( !renameOk ) {
renameOk = folderMan->startFromScratch(localFolder);
if( ! renameOk ) {
QMessageBox::StandardButton but;
but = QMessageBox::question( 0, tr("Folder rename failed"),
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
if( but == QMessageBox::Abort ) {
renameOk = true;
acceptCfg = false;
}
}
}
}
}
// Now write the resulting folder definition if folder names are set.
if( acceptCfg && urlHasChanged ) {
folderMan->removeAllFolderDefinitions();
folderMan->addFolderDefinition(Theme::instance()->appName(),
localFolder, _remoteFolder );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
} else {
// url is unchanged. Only the password was changed.
if( acceptCfg ) {
qDebug() << "Only password was changed, no changes to folder configuration.";
} else {
qDebug() << "User interrupted change of configuration.";
}
}
// save the user credentials and afterwards clear the cred store.
if( acceptCfg ) {
cfg.acceptCustomConfig();
}
}
// clear the custom config handle
_configHandle.clear();
ownCloudInfo::instance()->setCustomConfigHandle( QString::null );
// notify others.
emit ownCloudWizardDone( result );
}
void OwncloudSetupWizard::slotClearPendingRequests()
{
qDebug() << "Pending request: " << _mkdirRequestReply;
if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) {
qDebug() << "ABORTing pending mkdir request.";
_mkdirRequestReply->abort();
}
if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) {
qDebug() << "ABORTing pending check installation request.";
_checkInstallationRequest->abort();
}
if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) {
qDebug() << "ABORTing pending remote folder check request.";
_checkRemoteFolderRequest->abort();
}
}
} // ns Mirall
+56 -29
Ver Arquivo
@@ -21,54 +21,81 @@
#include <QNetworkReply>
#include <QPointer>
#include "mirall/owncloudwizard.h"
#include "mirall/theme.h"
namespace Mirall {
class OwncloudWizard;
class SiteCopyFolder;
class SyncResult;
class ownCloudInfo;
class FolderMan;
class OwncloudSetupWizard : public QObject
{
Q_OBJECT
public:
/** Run the wizard */
static void runWizard(QObject *obj, const char* amember, QWidget *parent = 0 );
explicit OwncloudSetupWizard( FolderMan *folderMan = 0, Theme *theme = 0, QObject *parent = 0 );
signals:
// overall dialog close signal.
void ownCloudWizardDone( int );
private slots:
void slotDetermineAuthType(const QString&);
void slotOwnCloudFoundAuth(const QString&, const QString&, const QString&, const QString&);
void slotAuthCheckReplyFinished();
void slotNoOwnCloudFoundAuth(QNetworkReply*);
void slotConnectToOCUrl(const QString&);
void slotConnectionCheck(const QString&, QNetworkReply*);
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
void slotAuthCheckReply(const QString&, QNetworkReply*);
void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError);
void slotAssistantFinished( int );
void slotClearPendingRequests();
private:
explicit OwncloudSetupWizard(QObject *parent = 0 );
~OwncloudSetupWizard();
/**
* @intro wether or not to show the intro wizard page
*/
void startWizard();
void testOwnCloudConnect();
void checkRemoteFolder(const QString& remoteFolder);
void installServer();
bool isBusy();
void writeOwncloudConfig();
/**
* returns the configured owncloud url if its already configured, otherwise an empty
* string.
*/
void setupLocalSyncFolder();
OwncloudWizard *wizard();
signals:
// issued if the oC Setup process (owncloud-admin) is finished.
void ownCloudSetupFinished( bool );
// overall dialog close signal.
void ownCloudWizardDone( int );
public slots:
protected slots:
// wizard dialog signals
void slotConnectToOCUrl( const QString& );
private slots:
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
void slotNoOwnCloudFound( QNetworkReply* );
void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError );
void slotAssistantFinished( int );
void slotClearPendingRequests();
void slotAuthCheckReply( const QString&, QNetworkReply * );
private:
bool createRemoteFolder();
void checkRemoteFolder();
void finalizeSetup( bool );
OwncloudWizard* _ocWizard;
/* Start a request to the newly installed ownCloud to check the connection */
void testOwnCloudConnect();
OwncloudWizard *_ocWizard;
QPointer<QNetworkReply> _mkdirRequestReply;
QPointer<QNetworkReply> _checkInstallationRequest;
QPointer<QNetworkReply> _checkRemoteFolderRequest;
QString _configHandle;
QString _remoteFolder;
FolderMan *_folderMan;
QString _configHandle;
QString _remoteFolder;
};
}
+11 -14
Ver Arquivo
@@ -52,28 +52,32 @@ QString ownCloudTheme::about() const
QString devString;
#ifdef GIT_SHA1
const QString githubPrefix(QLatin1String(
"https://github.com/owncloud/mirall/commit/"));
" https://github.com/owncloud/mirall/commit/"));
const QString gitSha1(QLatin1String(GIT_SHA1));
devString = QCoreApplication::translate("ownCloudTheme::about()",
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
" on %3, %4 using OCsync %5 and Qt %6.</small><p>")
" on %3, %4<br>using OCsync %5 and Qt %6.</small><p>")
.arg(githubPrefix+gitSha1).arg(gitSha1.left(6))
.arg(__DATE__).arg(__TIME__)
.arg(MIRALL_STRINGIFY(LIBCSYNC_VERSION))
.arg(QT_VERSION_STR);
#endif
return QCoreApplication::translate("ownCloudTheme::about()",
"<p>Version %2. "
"For more information visit <a href=\"%3\">%4</a></p>"
"<p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, ownCloud Inc.<br>"
"Based on Mirall by Duncan Mac-Vicar P.</small></p>"
"<p><b>%1 Client Version %2</b></p>"
"<p><b>Authors</b>"
"<br><a href=\"mailto:freitag@owncloud.com\">"
"Klaas Freitag</a>, ownCloud, Inc."
"<br><a href=\"mailto:danimo@owncloud.com\">"
"Daniel Molkentin</a>, ownCloud, Inc."
"<br><br>Based on Mirall by Duncan Mac-Vicar P.</p>"
"<p>For more information visit <a href=\"%3\">%4</a>.</p>"
"%7"
)
.arg(appName())
.arg(MIRALL_STRINGIFY(MIRALL_VERSION))
.arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN))
.arg(devString);
}
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
@@ -105,11 +109,6 @@ QVariant ownCloudTheme::customMedia(Theme::CustomMediaType type)
}
}
QString ownCloudTheme::helpUrl() const
{
return QString::fromLatin1("http://doc.owncloud.org/desktop/%1.%2/").arg(MIRALL_VERSION_MAJOR).arg(MIRALL_VERSION_MINOR);
}
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
{
return QColor("#1d2d42");
@@ -125,7 +124,5 @@ QPixmap ownCloudTheme::wizardHeaderLogo() const
return QPixmap(":/mirall/theme/colored/wizard_logo.png");
}
}
-2
Ver Arquivo
@@ -21,7 +21,6 @@ namespace Mirall {
class ownCloudTheme : public Theme
{
Q_OBJECT
public:
ownCloudTheme();
@@ -36,7 +35,6 @@ public:
QIcon applicationIcon() const;
QVariant customMedia(CustomMediaType type);
QString helpUrl() const;
QColor wizardHeaderBackgroundColor() const;
QColor wizardHeaderTitleColor() const;
+626
Ver Arquivo
@@ -0,0 +1,626 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "mirall/owncloudwizard.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "QProgressIndicator.h"
#include <QtCore>
#include <QtGui>
#include <stdlib.h>
namespace Mirall
{
void setupCustomMedia( QVariant variant, QLabel *label )
{
if( !label ) return;
QPixmap pix = variant.value<QPixmap>();
if( !pix.isNull() ) {
label->setPixmap(pix);
label->setAlignment( Qt::AlignTop | Qt::AlignRight );
label->setVisible(true);
} else {
QString str = variant.toString();
if( !str.isEmpty() ) {
label->setText( str );
label->setTextFormat( Qt::RichText );
label->setVisible(true);
label->setOpenExternalLinks(true);
}
}
}
// ======================================================================
OwncloudSetupPage::OwncloudSetupPage()
{
_ui.setupUi(this);
Theme *theme = Theme::instance();
setTitle( tr("<font color=\"%1\" size=\"5\">Connect to %2</font>")
.arg(theme->wizardHeaderTitleColor().name()).arg( theme->appNameGUI()));
setSubTitle( tr("<font color=\"%1\">Enter user credentials</font>")
.arg(theme->wizardHeaderTitleColor().name()));
registerField( QLatin1String("OCUrl"), _ui.leUrl );
registerField( QLatin1String("OCUser"), _ui.leUsername );
registerField( QLatin1String("OCPasswd"), _ui.lePassword);
registerField( QLatin1String("OCSyncFromScratch"), _ui.cbSyncFromScratch);
_ui.errorLabel->setVisible(true);
_ui.advancedBox->setVisible(false);
_progressIndi = new QProgressIndicator;
_ui.resultLayout->addWidget( _progressIndi );
_progressIndi->setVisible(false);
_ui.resultLayout->setEnabled(false);
// Error label
QString style = QLatin1String("border: 1px solid #eed3d7; border-radius: 5px; padding: 3px;"
"background-color: #f2dede; color: #b94a48;");
_ui.errorLabel->setStyleSheet( style );
_ui.errorLabel->setWordWrap(true);
_ui.errorLabel->setVisible(false);
_checking = false;
setupCustomization();
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SLOT(slotUserChanged(QString)));
connect( _ui.lePassword, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged()));
connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged()));
connect( _ui.cbAdvanced, SIGNAL(stateChanged (int)), SLOT(slotToggleAdvanced(int)));
connect( _ui.pbSelectLocalFolder, SIGNAL(clicked()), SLOT(slotSelectFolder()));
}
OwncloudSetupPage::~OwncloudSetupPage()
{
delete _progressIndi;
}
void OwncloudSetupPage::slotToggleAdvanced(int state)
{
_ui.advancedBox->setVisible( state == Qt::Checked );
slotHandleUserInput();
QSize size = wizard()->sizeHint();
// need to substract header for some reason
size -= QSize(0, 63);
wizard()->setMinimumSize(size);
wizard()->resize(size);
}
void OwncloudSetupPage::setOCUser( const QString & user )
{
_ocUser = user;
_ui.leUsername->setText(user);
}
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
{
_oCUrl = newUrl;
if( _oCUrl.isEmpty() ) {
_ui.leUrl->clear();
return;
}
_ui.leUrl->setText( _oCUrl );
}
void OwncloudSetupPage::setupCustomization()
{
// set defaults for the customize labels.
_ui.topLabel->hide();
_ui.bottomLabel->hide();
Theme *theme = Theme::instance();
QVariant variant = theme->customMedia( Theme::oCSetupTop );
if( !variant.isNull() ) {
setupCustomMedia( variant, _ui.topLabel );
}
variant = theme->customMedia( Theme::oCSetupBottom );
setupCustomMedia( variant, _ui.bottomLabel );
QString fixUrl = theme->overrideServerUrl();
if( !fixUrl.isEmpty() ) {
_ui.label_2->hide();
setServerUrl( fixUrl );
_ui.leUrl->setEnabled( false );
_ui.leUrl->hide();
}
}
void OwncloudSetupPage::slotUserChanged(const QString& user )
{
slotHandleUserInput();
}
// slot hit from textChanged of the url entry field.
void OwncloudSetupPage::slotUrlChanged(const QString& ocUrl)
{
slotHandleUserInput();
#if 0
QString url = ocUrl;
bool visible = false;
if (url.startsWith(QLatin1String("https://"))) {
_ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-high.png"));
_ui.urlLabel->setToolTip(tr("This url is secure. You can use it."));
visible = true;
}
if (url.startsWith(QLatin1String("http://"))) {
_ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-low.png"));
_ui.urlLabel->setToolTip(tr("This url is NOT secure. You should not use it."));
visible = true;
}
#endif
}
bool OwncloudSetupPage::isComplete() const
{
if( _ui.leUrl->text().isEmpty() ) return false;
if( _checking ) return false;
return !( _ui.lePassword->text().isEmpty() || _ui.leUsername->text().isEmpty() );
}
void OwncloudSetupPage::initializePage()
{
_connected = false;
_checking = false;
_multipleFoldersExist = false;
// call to init label
slotHandleUserInput();
if( _configExists ) {
_ui.lePassword->setFocus();
} else {
_ui.leUrl->setFocus();
}
}
bool OwncloudSetupPage::urlHasChanged()
{
bool change = false;
const QChar slash('/');
QUrl currentUrl( url() );
QUrl initialUrl( _oCUrl );
QString currentPath = currentUrl.path();
QString initialPath = initialUrl.path();
// add a trailing slash.
if( ! currentPath.endsWith( slash )) currentPath += slash;
if( ! initialPath.endsWith( slash )) initialPath += slash;
if( currentUrl.host() != initialUrl.host() ||
currentPath != initialPath ) {
change = true;
}
if( !change) { // no change yet, check the user.
QString user = _ui.leUsername->text().simplified();
if( user != _ocUser ) change = true;
}
return change;
}
// Called if the user changes the user- or url field. Adjust the texts and
// evtl. warnings on the dialog.
void OwncloudSetupPage::slotHandleUserInput()
{
// if the url has not changed, return.
if( ! urlHasChanged() ) {
// disable the advanced button as nothing has changed.
_ui.cbAdvanced->setEnabled(false);
_ui.advancedBox->setEnabled(false);
} else {
// Enable advanced stuff for new connection configuration.
_ui.cbAdvanced->setEnabled(true);
_ui.advancedBox->setEnabled(true);
}
const QString locFolder = localFolder();
// check if the local folder exists. If so, and if its not empty, show a warning.
QDir dir( locFolder );
QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
QString t;
if( !urlHasChanged() && _configExists ) {
// This is the password change mode: No change to the url and a config
// to an ownCloud exists.
t = tr("Change the Password for your configured account.");
} else {
// Complete new setup.
_ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder));
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
t = tr("Your entire account will be synced to the local folder '%1'.")
.arg(QDir::toNativeSeparators(locFolder));
} else {
t = tr("%1 folder '%2' is synced to local folder '%3'")
.arg(Theme::instance()->appName()).arg(_remoteFolder)
.arg(QDir::toNativeSeparators(locFolder));
}
if ( _multipleFoldersExist ) {
t += tr("<p><small><strong>Warning:</strong> You currently have multiple folders "
"configured. If you continue with the current settings, the folder configurations "
"will be discarded and a single root folder sync will be created!</small></p>");
}
if( entries.count() > 0) {
// the directory is not empty
if (!_ui.cbAdvanced->isChecked()) {
t += tr("<p><small><strong>Warning:</strong> The local directory is not empty. "
"Pick a resolution in the advanced settings!</small></p>");
}
_ui.resolutionWidget->setVisible(true);
} else {
// the dir is empty, which means that there is no problem.
_ui.resolutionWidget->setVisible(false);
}
}
_ui.syncModeLabel->setText(t);
_ui.syncModeLabel->setFixedHeight(_ui.syncModeLabel->sizeHint().height());
}
int OwncloudSetupPage::nextId() const
{
return OwncloudWizard::Page_Result;
}
QString OwncloudSetupPage::url() const
{
QString url = _ui.leUrl->text().simplified();
return url;
}
QString OwncloudSetupPage::localFolder() const
{
QString folder = wizard()->property("localFolder").toString();
return folder;
}
void OwncloudSetupPage::setConnected( bool comp )
{
_connected = comp;
_ui.resultLayout->setEnabled(true);
_progressIndi->setVisible(false);
_progressIndi->stopAnimation();
}
bool OwncloudSetupPage::validatePage()
{
bool re = false;
if( ! _connected) {
setErrorString(QString::null);
_checking = true;
_ui.resultLayout->setEnabled(true);
_progressIndi->setVisible(true);
_progressIndi->startAnimation();
emit completeChanged();
emit connectToOCUrl( url() );
return false;
} else {
// connecting is running
stopSpinner();
_checking = false;
emit completeChanged();
return true;
}
}
void OwncloudSetupPage::setErrorString( const QString& err )
{
if( err.isEmpty()) {
_ui.errorLabel->setVisible(false);
} else {
_ui.errorLabel->setVisible(true);
_ui.errorLabel->setText(err);
}
_checking = false;
emit completeChanged();
stopSpinner();
}
void OwncloudSetupPage::stopSpinner()
{
_ui.resultLayout->setEnabled(false);
_progressIndi->setVisible(false);
_progressIndi->stopAnimation();
}
OwncloudSetupPage::SyncMode OwncloudSetupPage::syncMode()
{
return BoxMode;
}
void OwncloudSetupPage::setRemoteFolder( const QString& remoteFolder )
{
if( !remoteFolder.isEmpty() ) {
_remoteFolder = remoteFolder;
}
}
void OwncloudSetupPage::setMultipleFoldersExist(bool exist)
{
_multipleFoldersExist = exist;
}
void OwncloudSetupPage::slotSelectFolder()
{
QString dir = QFileDialog::getExistingDirectory(0, tr("Local Sync Folder"), QDir::homePath());
if( !dir.isEmpty() ) {
_ui.pbSelectLocalFolder->setText(dir);
wizard()->setProperty("localFolder", dir);
slotHandleUserInput();
}
}
OwncloudSetupPage::SyncMode OwncloudWizard::syncMode()
{
return _setupPage->syncMode();
return OwncloudSetupPage::BoxMode;
}
void OwncloudWizard::setMultipleFoldersExist(bool exist)
{
_setupPage->setMultipleFoldersExist(exist);
}
void OwncloudSetupPage::setConfigExists( bool config )
{
_configExists = config;
if (config == true) {
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
}
}
// ======================================================================
OwncloudWizardResultPage::OwncloudWizardResultPage()
{
_ui.setupUi(this);
// no fields to register.
Theme *theme = Theme::instance();
setTitle( tr("<font color=\"%1\" size=\"5\">Everything set up!</font>")
.arg(theme->wizardHeaderTitleColor().name()));
// required to show header in QWizard's modern style
setSubTitle( QLatin1String(" ") );
_ui.pbOpenLocal->setText("Open local folder");
_ui.pbOpenServer->setText(tr("Open %1").arg(Theme::instance()->appNameGUI()));
_ui.pbOpenLocal->setIcon(QIcon(":/mirall/resources/folder-sync.png"));
_ui.pbOpenLocal->setText(tr("Open Local Folder"));
_ui.pbOpenLocal->setIconSize(QSize(48, 48));
connect(_ui.pbOpenLocal, SIGNAL(clicked()), SLOT(slotOpenLocal()));
_ui.pbOpenLocal->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
QIcon appIcon = theme->applicationIcon();
_ui.pbOpenServer->setIcon(appIcon.pixmap(48));
_ui.pbOpenServer->setText(tr("Open %1").arg(theme->appNameGUI()));
_ui.pbOpenServer->setIconSize(QSize(48, 48));
_ui.pbOpenServer->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
connect(_ui.pbOpenServer, SIGNAL(clicked()), SLOT(slotOpenServer()));
setupCustomization();
}
OwncloudWizardResultPage::~OwncloudWizardResultPage()
{
}
void OwncloudWizardResultPage::setComplete(bool complete)
{
_complete = complete;
emit completeChanged();
}
bool OwncloudWizardResultPage::isComplete() const
{
return _complete;
}
void OwncloudWizardResultPage::initializePage()
{
const QString localFolder = wizard()->property("localFolder").toString();
QString text;
if( _remoteFolder == QLatin1String("/") || _remoteFolder.isEmpty() ) {
text = tr("Your entire account is synced to the local folder <i>%1</i>")
.arg(QDir::toNativeSeparators(localFolder));
} else {
text = tr("ownCloud folder <i>%1</i> is synced to local folder <i>%2</i>")
.arg(_remoteFolder).arg(QDir::toNativeSeparators(localFolder));
}
_ui.localFolderLabel->setText( text );
}
void OwncloudWizardResultPage::setRemoteFolder(const QString &remoteFolder)
{
_remoteFolder = remoteFolder;
}
void OwncloudWizardResultPage::setupCustomization()
{
// set defaults for the customize labels.
_ui.topLabel->setText( QString::null );
_ui.topLabel->hide();
QVariant variant = Theme::instance()->customMedia( Theme::oCSetupResultTop );
setupCustomMedia( variant, _ui.topLabel );
}
// ======================================================================
/**
* Folder wizard itself
*/
OwncloudWizard::OwncloudWizard(QWidget *parent)
: QWizard(parent),
_configExists(false)
{
_setupPage = new OwncloudSetupPage;
_resultPage = new OwncloudWizardResultPage;
setPage(Page_oCSetup, _setupPage );
setPage(Page_Result, _resultPage );
// note: start Id is set by the calling class depending on if the
// welcome text is to be shown or not.
setWizardStyle( QWizard::ModernStyle );
connect( this, SIGNAL(currentIdChanged(int)), SLOT(slotCurrentPageChanged(int)));
connect( _setupPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString)));
Theme *theme = Theme::instance();
setWizardStyle(QWizard::ModernStyle);
setPixmap( QWizard::BannerPixmap, theme->wizardHeaderBanner() );
setPixmap( QWizard::LogoPixmap, theme->wizardHeaderLogo() );
setOption( QWizard::NoBackButtonOnStartPage );
setOption( QWizard::NoBackButtonOnLastPage );
setOption( QWizard::NoCancelButton );
setTitleFormat(Qt::RichText);
setSubTitleFormat(Qt::RichText);
}
QString OwncloudWizard::localFolder() const
{
return(_setupPage->localFolder());
}
QString OwncloudWizard::ocUrl() const
{
QString url = field("OCUrl").toString().simplified();
return url;
}
void OwncloudWizard::enableFinishOnResultWidget(bool enable)
{
_resultPage->setComplete(enable);
}
void OwncloudWizard::setRemoteFolder( const QString& remoteFolder )
{
_setupPage->setRemoteFolder( remoteFolder );
_resultPage->setRemoteFolder( remoteFolder );
}
void OwncloudWizard::showConnectInfo( const QString& msg )
{
if( _setupPage ) {
_setupPage->setErrorString( msg );
}
}
void OwncloudWizard::successfullyConnected(bool enable)
{
_setupPage->setConnected( enable );
if( enable ) {
next();
}
}
void OwncloudWizard::slotCurrentPageChanged( int id )
{
qDebug() << "Current Wizard page changed to " << id;
if( id == Page_oCSetup ) {
setButtonText( QWizard::NextButton, tr("Connect...") );
emit clearPendingRequests();
_setupPage->initializePage();
}
if( id == Page_Result ) {
appendToConfigurationLog( QString::null );
}
}
void OwncloudWizard::displayError( const QString& msg )
{
_setupPage->setErrorString( msg );
}
void OwncloudWizard::appendToConfigurationLog( const QString& msg, LogType type )
{
_setupLog << msg;
qDebug() << "Setup-Log: " << msg;
}
void OwncloudWizard::setOCUrl( const QString& url )
{
_setupPage->setServerUrl( url );
}
void OwncloudWizard::setOCUser( const QString& user )
{
_oCUser = user;
_setupPage->setOCUser( user );
}
void OwncloudWizard::setConfigExists( bool config )
{
_configExists = config;
_setupPage->setConfigExists( config );
}
bool OwncloudWizard::configExists()
{
return _configExists;
}
void OwncloudWizardResultPage::slotOpenLocal()
{
const QString localFolder = wizard()->property("localFolder").toString();
QDesktopServices::openUrl(QUrl::fromLocalFile(localFolder));
}
void OwncloudWizardResultPage::slotOpenServer()
{
QUrl url = field("OCUrl").toUrl();
qDebug() << Q_FUNC_INFO << url;
QDesktopServices::openUrl(url);
}
} // end namespace
+191
Ver Arquivo
@@ -0,0 +1,191 @@
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* Copyright (C) by Klaas Freitag <freitag@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_OWNCLOUDWIZARD_H
#define MIRALL_OWNCLOUDWIZARD_H
#include <QWizard>
#include "ui_owncloudsetuppage_ng.h"
#include "ui_owncloudwizardresultpage.h"
class QLabel;
class QVariant;
class QProgressIndicator;
namespace Mirall {
class OwncloudSetupPage;
class OwncloudWizardResultPage;
class OwncloudSetupPage: public QWizardPage
{
Q_OBJECT
public:
OwncloudSetupPage();
~OwncloudSetupPage();
enum SyncMode {
SelectiveMode,
BoxMode
};
virtual bool isComplete() const;
virtual void initializePage();
virtual int nextId() const;
void setServerUrl( const QString& );
void setOCUser( const QString& );
void setAllowPasswordStorage( bool );
bool validatePage();
QString url() const;
QString localFolder() const;
void setConnected(bool complete);
void setRemoteFolder( const QString& remoteFolder);
void setMultipleFoldersExist( bool exist );
SyncMode syncMode();
public slots:
void setErrorString( const QString& );
void setConfigExists( bool );
void stopSpinner();
protected slots:
void slotUrlChanged(const QString&);
void slotUserChanged(const QString&);
void setupCustomization();
void slotToggleAdvanced(int state);
void slotSelectFolder();
signals:
void connectToOCUrl( const QString& );
protected:
void updateFoldersInfo();
private slots:
void slotHandleUserInput();
private:
bool urlHasChanged();
Ui_OwncloudSetupPage _ui;
QString _oCUrl;
QString _ocUser;
bool _connected;
bool _checking;
bool _configExists;
bool _multipleFoldersExist;
QProgressIndicator *_progressIndi;
QButtonGroup *_selectiveSyncButtons;
QString _remoteFolder;
};
class OwncloudWizard: public QWizard
{
Q_OBJECT
public:
enum {
Page_oCSetup,
Page_Result
};
enum LogType {
LogPlain,
LogParagraph
};
OwncloudWizard(QWidget *parent = 0);
void setOCUrl( const QString& );
void setOCUser( const QString& );
void setupCustomMedia( QVariant, QLabel* );
QString ocUrl() const;
QString localFolder() const;
void enableFinishOnResultWidget(bool enable);
void displayError( const QString& );
OwncloudSetupPage::SyncMode syncMode();
void setMultipleFoldersExist( bool );
void setConfigExists( bool );
bool configExists();
public slots:
void setRemoteFolder( const QString& );
void appendToConfigurationLog( const QString& msg, LogType type = LogParagraph );
void slotCurrentPageChanged( int );
void showConnectInfo( const QString& );
void successfullyConnected(bool);
signals:
void clearPendingRequests();
void connectToOCUrl( const QString& );
private:
OwncloudSetupPage *_setupPage;
OwncloudWizardResultPage *_resultPage;
QString _configFile;
QString _oCUser;
QStringList _setupLog;
bool _configExists;
};
/**
* page to ask for the type of Owncloud to connect to
*/
/**
* page to display the install result
*/
class OwncloudWizardResultPage : public QWizardPage
{
Q_OBJECT
public:
OwncloudWizardResultPage();
~OwncloudWizardResultPage();
bool isComplete() const;
void initializePage();
void setRemoteFolder( const QString& remoteFolder);
public slots:
void setComplete(bool complete);
protected slots:
void slotOpenLocal();
void slotOpenServer();
protected:
void setupCustomization();
private:
QString _localFolder;
QString _remoteFolder;
bool _complete;
Ui_OwncloudWizardResultPage _ui;
};
} // ns Mirall
#endif

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais