Comparar commits
134 Commits
http2_x100
...
master
| Autor | SHA1 | Data | |
|---|---|---|---|
| 172689d35c | |||
| 60a4a742a3 | |||
| b26db062d2 | |||
| 611f633ba8 | |||
| 3265948458 | |||
| 0e3e9d5991 | |||
| 0be6cd3bf7 | |||
| 867b78052d | |||
| 058f7df635 | |||
| c1552d7984 | |||
| 575b981542 | |||
| 0d0af95956 | |||
| 6c5d873647 | |||
| 71187e1744 | |||
| 006ce854a6 | |||
| 697178bab6 | |||
| d8a86da377 | |||
| d1dace9e7f | |||
| 1cec2ca13d | |||
| 1d9e08d109 | |||
| 7879c470b3 | |||
| 3c7545a45f | |||
| 4c1fdf1dee | |||
| 18e25122db | |||
| 439e688906 | |||
| 4198d9f420 | |||
| 06579a5c70 | |||
| df773ea8bb | |||
| e7be4faac8 | |||
| a184c6bec1 | |||
| 1102ac20ac | |||
| 6a4ae63f14 | |||
| 6c6961e4d9 | |||
| 78a798eef3 | |||
| 19dd656989 | |||
| d9fac50e9b | |||
| 9614a94035 | |||
| 5002964546 | |||
| 4cca1ba55f | |||
| 3e99c32582 | |||
| 74ce597f8d | |||
| a27b2d94b3 | |||
| 890e771ec1 | |||
| 5df10cb8f8 | |||
| 9acc974268 | |||
| 42e64026ae | |||
| 78e7d13f9f | |||
| 2d55332a45 | |||
| 72cd9abd4a | |||
| 0d16cf41fe | |||
| 65e4afedc4 | |||
| b76a9654cc | |||
| 38cf459b3e | |||
| ed7416098e | |||
| 517623e457 | |||
| f89bc09fd1 | |||
| f854c5263b | |||
| 70da607e06 | |||
| 4f28b2daad | |||
| 8884fe7236 | |||
| bb3efc5988 | |||
| f6665ccc81 | |||
| f1e9be4fa8 | |||
| 9db23d4df1 | |||
| 9d16ad844c | |||
| b0700ebbab | |||
| 2bda55be81 | |||
| e859d220be | |||
| c3ae5123cb | |||
| a1a5111a8a | |||
| ee211d7609 | |||
| 1fc5a76622 | |||
| a764d7eb86 | |||
| 605a18ff73 | |||
| 92e86641d1 | |||
| c8cfb3160e | |||
| 268fc97a71 | |||
| de2458d892 | |||
| d75b838897 | |||
| 4df7cab72a | |||
| 59c1fdbe05 | |||
| 26234dbf6c | |||
| 05a254b527 | |||
| d282a8380e | |||
| 83dfbb933b | |||
| 100603fdc0 | |||
| d6fdda8efa | |||
| faedaa5e09 | |||
| 8a70d22af7 | |||
| a63d970e5e | |||
| f6c77fad17 | |||
| 661c7f0558 | |||
| a7efe144fc | |||
| b68a28de8d | |||
| 72a7b7ca42 | |||
| 166ef85a51 | |||
| 1f60c61f87 | |||
| 30ef794fa1 | |||
| 47fbfbc006 | |||
| e131c142ff | |||
| 1b99ff2e91 | |||
| 3e85d47a57 | |||
| e709d75d56 | |||
| cb5cfb8cf6 | |||
| ebd2a15711 | |||
| d3a0608bd5 | |||
| c25b599bbb | |||
| a5ff9e58e3 | |||
| 9b96899d75 | |||
| b046cca010 | |||
| edf0a99a8a | |||
| a4640b202f | |||
| 5ef2e88f00 | |||
| 352f168313 | |||
| 85d3de1589 | |||
| 588a88fb63 | |||
| cd9e88ad22 | |||
| 29b39acfbe | |||
| 7427be0062 | |||
| e7546903cc | |||
| 78e3a7e897 | |||
| 1a21b8698e | |||
| 280906eab9 | |||
| 9d7425b201 | |||
| 7eb43d7f7e | |||
| d76e0ec6d8 | |||
| 0249a68420 | |||
| aa6f041c36 | |||
| dce3f8c4f6 | |||
| 4a83f976e1 | |||
| 23572aaf77 | |||
| 48655ff1ec | |||
| ffbf34cb97 | |||
| fad690be11 |
+2
-3
@@ -7,6 +7,8 @@ endif()
|
||||
|
||||
project(client)
|
||||
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
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 )
|
||||
@@ -58,9 +60,6 @@ if( UNIX AND NOT APPLE )
|
||||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
+5
-4
@@ -1,10 +1,11 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
version 2.3.0 (2017-02-xx)
|
||||
* Decreased memory usage during sync
|
||||
* Overlay icons: Lower CPU usage
|
||||
* Allow to not sync the server's external storages by default
|
||||
* Switch Windows and OS X build to 5.6.2
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
|
||||
externo
+1
-1
@@ -39,7 +39,7 @@ node('CLIENT') {
|
||||
|
||||
|
||||
stage 'Win32'
|
||||
def win32 = docker.image('deepdiver/docker-owncloud-client-win32:latest')
|
||||
def win32 = docker.image('guruz/docker-owncloud-client-win32:latest')
|
||||
win32.pull() // make sure we have the latest available from Docker Hub
|
||||
win32.inside {
|
||||
sh '''
|
||||
|
||||
@@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Показати примітки
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Знайдено процес(и) ${APPLICATION_EXECUTABLE}, які необхідно зупинити.$\nХочете щоб програма установки зробила це самостійно?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Завершення процесів ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Не знайдено процеси, які необхідно зупинити!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Знайдено застарілу версію програми ${APPLICATION_NAME}. Рекомендуємо її спочатку видалити. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "У вашої системі встановлена застаріла версія додатку ${APPLICATION_NAME}. Рекомендуємо видалити її перед початком встановлення поточної версії. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Видалити перед установкою"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
||||
|
||||
+1
-1
Submodule binary updated: 0d89ac7766...741b49156b
@@ -418,10 +418,8 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Network.dll"
|
||||
File "${QT_DLL_PATH}\Qt5OpenGL.dll"
|
||||
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Quick.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||
@@ -435,9 +433,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata53.dll"
|
||||
File "${MING_BIN}\icui18n53.dll"
|
||||
File "${MING_BIN}\icuuc53.dll"
|
||||
File "${MING_BIN}\icudata56.dll"
|
||||
File "${MING_BIN}\icui18n56.dll"
|
||||
File "${MING_BIN}\icuuc56.dll"
|
||||
File "${MING_BIN}\libEGL.dll"
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
@@ -446,11 +444,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwebp-4.dll"
|
||||
File "${MING_BIN}\libwebp-5.dll"
|
||||
File "${MING_BIN}\libxslt-1.dll"
|
||||
File "${MING_BIN}\libxml2-2.dll"
|
||||
File "${MING_BIN}\zlib1.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MING_BIN}\libharfbuzz-0.dll"
|
||||
File "${MING_BIN}\libfreetype-6.dll"
|
||||
File "${MING_BIN}\libglib-2.0-0.dll"
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
|
||||
;QtKeyChain stuff
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
|
||||
@@ -28,7 +28,6 @@ include(ConfigureChecks.cmake)
|
||||
|
||||
|
||||
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@@ -41,7 +40,7 @@ endif (MEM_NULL_TESTS)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
set(WITH_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
|
||||
@@ -26,4 +26,4 @@
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ASPRINTF 1
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
#cmakedefine WITH_TESTING 1
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifndef WITH_UNIT_TESTING
|
||||
#ifndef WITH_TESTING
|
||||
static
|
||||
#endif
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||
|
||||
@@ -36,7 +36,7 @@ enum csync_exclude_type_e {
|
||||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ struct csync_s {
|
||||
|
||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
||||
|
||||
|
||||
csync_vio_opendir_hook remote_opendir_hook;
|
||||
@@ -207,7 +207,7 @@ __attribute__ ((packed))
|
||||
#endif
|
||||
;
|
||||
|
||||
void csync_file_stat_free(csync_file_stat_t *st);
|
||||
OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st);
|
||||
|
||||
/*
|
||||
* context for the treewalk function
|
||||
|
||||
@@ -56,17 +56,15 @@ int csync_get_statedb_exists(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred with errno set.
|
||||
*/
|
||||
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||
OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||
|
||||
int csync_statedb_close(CSYNC *ctx);
|
||||
OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||
|
||||
char *csync_statedb_get_etag(CSYNC *ctx, uint64_t jHash);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||
|
||||
/**
|
||||
* @brief Query all files metadata inside and below a path.
|
||||
|
||||
@@ -436,7 +436,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
|
||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
|
||||
csync_file_stat_free(st);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+11
-6
@@ -77,7 +77,7 @@ a synchronization process.
|
||||
|
||||
Before the 1.3.0 release of the Desktop Client, the synchronization process
|
||||
might create false conflict files if time deviates. Original and changed files
|
||||
conflict only in their timestamp, but not in their content. This behaviour was
|
||||
conflict only in their timestamp, but not in their content. This behavior was
|
||||
changed to employ a binary check if files differ.
|
||||
|
||||
Like files, directories also hold a unique ID that changes whenever one of the
|
||||
@@ -132,11 +132,16 @@ changed and no synchronization occurs.
|
||||
In the event a file has changed on both the local and the remote repository
|
||||
since the last sync run, it can not easily be decided which version of the file
|
||||
is the one that should be used. However, changes to any side will not be lost. Instead,
|
||||
a *conflict case* is created. The client resolves this conflict by creating a
|
||||
conflict file of the older of the two files and saving the newer file under the
|
||||
original file name. Conflict files are always created on the client and never
|
||||
on the server. The conflict file uses the same name as the original file, but
|
||||
is appended with the timestamp of the conflict detection.
|
||||
a *conflict case* is created. The client resolves this conflict by renaming the
|
||||
local file, appending a conflict label and timestamp, and saving the remote file
|
||||
under the original file name.
|
||||
|
||||
Example: Assume there is a conflict in message.txt because its contents have
|
||||
changed both locally and remotely since the last sync run. The local file with
|
||||
the local changes will be renamed to message_conflict-20160101-153110.txt and
|
||||
the remote file will be downloaded and saved as message.txt.
|
||||
|
||||
Conflict files are always created on the client and never on the server.
|
||||
|
||||
|
||||
.. _ignored-files-label:
|
||||
|
||||
+3
-20
@@ -3,7 +3,7 @@ The Automatic Updater
|
||||
=====================
|
||||
|
||||
The Automatic Updater ensures that you always have the
|
||||
latest features and bugfixes for your ownCloud synchronization client.
|
||||
latest features and bug fixes for your ownCloud synchronization client.
|
||||
|
||||
The Automatic Updater updates only on Mac OS X and Windows computers; Linux
|
||||
users only need to use their normal package managers. However, on Linux systems
|
||||
@@ -49,7 +49,6 @@ the Linux operating system do not perform any updates on their own. The client
|
||||
will inform you (``Settings -> General -> Updates``) when an update is
|
||||
available.
|
||||
|
||||
|
||||
Preventing Automatic Updates
|
||||
----------------------------
|
||||
|
||||
@@ -110,24 +109,8 @@ To prevent automatic updates and disallow manual overrides:
|
||||
Preventing Automatic Updates in Mac OS X Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can disable the automatic update mechanism in Mac OS X operating systems
|
||||
using the system-wide ``.plist`` file. To access this file:
|
||||
|
||||
1. Go to this directory::
|
||||
|
||||
/Library/Preferences/
|
||||
|
||||
2. Locate and open the following file::
|
||||
|
||||
com.owncloud.desktopclient.plist
|
||||
|
||||
3. Add a new root level item of type ``bool``.
|
||||
|
||||
4. Name the item ``skipUpdateCheck``.
|
||||
|
||||
5. Set the item to ``true``.
|
||||
|
||||
Alternatively, you can copy the file
|
||||
You can disable the automatic update mechanism, in the Mac OS X operating system,
|
||||
by copying the file
|
||||
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist``
|
||||
to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
|
||||
|
||||
|
||||
+12
-8
@@ -54,7 +54,7 @@ distribution. Make sure the repositories for source packages are enabled.
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
In additon to needing XCode (along with the command line tools), developing in
|
||||
In addition to needing XCode (along with the command line tools), developing in
|
||||
the Mac OS X environment requires extra dependencies. You can install these
|
||||
dependencies through MacPorts_ or Homebrew_. These dependencies are required
|
||||
only on the build machine, because non-standard libs are deployed in the app
|
||||
@@ -77,25 +77,29 @@ To set up your build environment for development using HomeBrew_:
|
||||
|
||||
brew tap owncloud/owncloud
|
||||
|
||||
5. Install any missing dependencies::
|
||||
5. Install a Qt5 version with qtwebkit support::
|
||||
|
||||
brew install qt5 --with-qtwebkit
|
||||
|
||||
6. Install any missing dependencies::
|
||||
|
||||
brew install $(brew deps owncloud-client)
|
||||
|
||||
3. Add Qt from brew to the path::
|
||||
7. Add Qt from brew to the path::
|
||||
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||
|
||||
Where ``x.z`` is the current version of Qt 5 that brew has installed
|
||||
Where ``x.y`` is the current version of Qt 5 that brew has installed
|
||||
on your machine.
|
||||
4. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
make sure you make the same install prefix as later while building the client e.g. -
|
||||
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
||||
|
||||
5. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
|
||||
6. Install the Packages_ package creation tool.
|
||||
10. Install the Packages_ package creation tool.
|
||||
|
||||
7. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
<install_dir>``. If you have a developer signing certificate, you can specify
|
||||
its Common Name as a third parameter (use quotes) to have the package
|
||||
signed automatically.
|
||||
|
||||
+8
-3
@@ -16,15 +16,20 @@ format. You can overwrite changes using the ownCloud configuration dialog.
|
||||
.. note:: Use caution when making changes to the ownCloud Client configuration
|
||||
file. Incorrect settings can produce unintended results.
|
||||
|
||||
You can change the following configuration settings (must be under the ``[ownCloud]`` section)
|
||||
You can change the following configuration settings in the ``[ownCloud]`` section:
|
||||
|
||||
- ``remotePollInterval`` (default: ``30000``) -- Specifies the poll time for the remote repository in milliseconds.
|
||||
|
||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||
- ``forceSyncInterval`` (default: ``7200000``) -- The duration of no activity after which a synchronization run shall be triggered automatically.
|
||||
|
||||
- ``notificationRefreshInterval`` (default: ``300000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
||||
|
||||
You can change the following configuration settings in the ``[General]`` section:
|
||||
|
||||
- ``chunkSize`` (default: ``5242880``) -- Specifies the chunk size of uploaded files in bytes.
|
||||
|
||||
- ``promptDeleteAllFiles`` (default: ``true``) -- If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted.
|
||||
|
||||
- ``notificationRefreshInterval`` (default``300,000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||
|
||||
- ``timeout`` (default: ``300``) -- The timeout for network connections in seconds.
|
||||
|
||||
+9
-6
@@ -1,17 +1,20 @@
|
||||
FAQ
|
||||
===
|
||||
|
||||
**Issue:**
|
||||
|
||||
Some files are continuously uploaded to the server, even when they are not modified.
|
||||
|
||||
**Resolution:**
|
||||
------------------------------------------------------------------------------------
|
||||
|
||||
It is possible that another program is changing the modification date of the file.
|
||||
|
||||
If the file is uses the ``.eml`` extension, Windows automatically and
|
||||
continually changes all files, unless you remove
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers``
|
||||
from the windows registry.
|
||||
|
||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
||||
|
||||
Syncing breaks when attempting to sync deeper than 50 sub-directories, but the sync client does not report an error (RC=0)
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The sync client has been intentionally limited to sync no deeper than
|
||||
fifty sub-directories, to help prevent memory problems.
|
||||
Unfortunately, it, *currently*, does not report an error when this occurs.
|
||||
However, a UI notification is planned for a future release of ownCloud.
|
||||
|
||||
@@ -50,6 +50,21 @@ Identifying Basic Functionality Problems
|
||||
As an example, after installing the ``cadaver`` app, you can issue the
|
||||
``propget`` command to obtain various properties pertaining to the current
|
||||
directory and also verify WebDAV server connection.
|
||||
|
||||
"CSync unknown error"
|
||||
---------------------
|
||||
|
||||
If you see this error message stop your client, delete the
|
||||
``.csync_journal.db`` file, and then restart your client.
|
||||
There is a ``.csync_journal.db`` file inside the folder of every account
|
||||
configured on your client.
|
||||
|
||||
.. NOTE::
|
||||
Please note that this will also erase some of your settings about which
|
||||
files to download.
|
||||
|
||||
See https://github.com/owncloud/client/issues/5226 for more discussion of this
|
||||
issue.
|
||||
|
||||
|
||||
Isolating other issues
|
||||
|
||||
@@ -138,7 +138,7 @@ Network
|
||||
|
||||
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
|
||||
|
||||
This tab consollidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
||||
This tab consolidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
||||
|
||||
.. image:: images/settings_network.png
|
||||
:scale: 50 %
|
||||
@@ -152,7 +152,7 @@ Proxy Settings
|
||||
On Linux, this will only pick up the value of the variable ``http_proxy``.
|
||||
* ``Specify proxy manually as``: Allows to specify custom proxy settings.
|
||||
If you require to go through a HTTP(S) proxy server such as Squid or Microsoft
|
||||
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particulary
|
||||
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particularly
|
||||
useful in special company LAN setups, or in combination with the OpenSSH
|
||||
dynamic application level forwarding feature (see ``ssh -D``).
|
||||
* ``Host``: Enter the host name or IP address of your proxy server, followed
|
||||
|
||||
@@ -37,6 +37,10 @@ Operating system:
|
||||
|
||||
OS language:
|
||||
|
||||
Qt version used by client package (Linux only, see also Settings dialog):
|
||||
|
||||
Client package (From ownCloud or distro) (Linux only):
|
||||
|
||||
Installation path of client:
|
||||
|
||||
### Logs
|
||||
|
||||
+107
-8
@@ -625,6 +625,96 @@ X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
@@ -650,7 +740,9 @@ Comment[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||
GenericName[ja_JP]=フォルダー同期
|
||||
Name[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||
Icon[ja_JP]=@APPLICATION_EXECUTABLE@
|
||||
Comment[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
GenericName[el]=Συγχρονισμός φακέλου
|
||||
Name[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
Icon[el]=@APPLICATION_EXECUTABLE@
|
||||
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
|
||||
GenericName[en_GB]=Folder Sync
|
||||
@@ -664,10 +756,13 @@ Comment[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||
GenericName[de_DE]=Ordner-Synchronisation
|
||||
Name[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||
Icon[de_DE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
GenericName[fa]=همسان سازی پوشهها
|
||||
Name[fa]=@APPLICATION_EXECUTABLE@ نسخهی همسان سازی مشتری
|
||||
Icon[fa]=@APPLICATION_EXECUTABLE@
|
||||
Comment[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
GenericName[fr]=Dossier de Synchronisation
|
||||
Name[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
@@ -676,6 +771,10 @@ Comment[he]=@APPLICATION_NAME@ לקוח סנכון שולחן עבודה
|
||||
GenericName[he]=סנכון תיקייה
|
||||
Name[he]=@APPLICATION_NAME@ לקוח סנכרון שולחן עבודה
|
||||
Icon[he]=@APPLICATION_EXECUTABLE@
|
||||
Comment[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
||||
GenericName[ia]=Synchronisar Dossier
|
||||
Name[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
||||
Icon[ia]=@APPLICATION_EXECUTABLE@
|
||||
Comment[id]=Klien sinkronisasi desktop @APPLICATION_NAME@
|
||||
GenericName[id]=Folder Sync
|
||||
Name[id]=Klien sync desktop @APPLICATION_NAME@
|
||||
@@ -703,10 +802,10 @@ Comment[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||
GenericName[et_EE]=Kaustade sünkroonimine
|
||||
Name[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||
Icon[et_EE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização do computador
|
||||
GenericName[pt_BR]=Sincronização de Pasta
|
||||
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização de desktop
|
||||
|
||||
@@ -16,12 +16,13 @@ set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/ownCloud.icns")
|
||||
# those user-defined settings to build the plist.
|
||||
add_custom_target( mac_overlayplugin ALL
|
||||
xcodebuild -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj
|
||||
-target FinderSyncExt -configuration Release SYMROOT=${CMAKE_CURRENT_BINARY_DIR}
|
||||
OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}
|
||||
OC_APPLICATION_NAME="${APPLICATION_NAME}"
|
||||
OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}
|
||||
OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}
|
||||
COMMENT building Mac Overlay icons)
|
||||
-target FinderSyncExt -configuration Release "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}"
|
||||
"OC_APPLICATION_NAME=${APPLICATION_NAME}"
|
||||
"OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
|
||||
"OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
|
||||
COMMENT building Mac Overlay icons
|
||||
VERBATIM)
|
||||
add_dependencies(mac_overlayplugin ${APPLICATION_EXECUTABLE}) # for the ownCloud.icns to be generated
|
||||
|
||||
|
||||
|
||||
@@ -155,9 +155,13 @@
|
||||
{
|
||||
_shareMenuTitle = nil;
|
||||
|
||||
[_registeredDirectories removeAllObjects];
|
||||
// For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
|
||||
// we reset the directoryURLs (seen on macOS 10.12 at least).
|
||||
// First setting it to the FS root and then setting it to nil seems to work around the issue.
|
||||
[FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
|
||||
// This will tell Finder that this extension isn't attached to any directory
|
||||
// until we can reconnect to the sync client.
|
||||
[_registeredDirectories removeAllObjects];
|
||||
[FIFinderSyncController defaultController].directoryURLs = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,54 +36,54 @@ using namespace std;
|
||||
|
||||
OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo()
|
||||
{
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return {};
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return {};
|
||||
}
|
||||
socket.SendMsg(L"SHARE_MENU_TITLE\n");
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return {};
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return {};
|
||||
}
|
||||
socket.SendMsg(L"SHARE_MENU_TITLE\n");
|
||||
|
||||
ContextMenuInfo info;
|
||||
std::wstring response;
|
||||
int sleptCount = 0;
|
||||
while (sleptCount < 5) {
|
||||
if (socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH
|
||||
info.watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) {
|
||||
info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE:
|
||||
break; // Stop once we received the last sent request
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sleep(50);
|
||||
++sleptCount;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
ContextMenuInfo info;
|
||||
std::wstring response;
|
||||
int sleptCount = 0;
|
||||
while (sleptCount < 5) {
|
||||
if (socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH
|
||||
info.watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) {
|
||||
info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE:
|
||||
break; // Stop once we received the last sent request
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sleep(50);
|
||||
++sleptCount;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void OCClientInterface::ShareObject(const std::wstring &path)
|
||||
{
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return;
|
||||
}
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t msg[SOCK_BUFFER] = { 0 };
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str())))
|
||||
{
|
||||
socket.SendMsg(msg);
|
||||
}
|
||||
wchar_t msg[SOCK_BUFFER] = { 0 };
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str())))
|
||||
{
|
||||
socket.SendMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ class CommunicationSocket;
|
||||
class OCClientInterface
|
||||
{
|
||||
public:
|
||||
struct ContextMenuInfo {
|
||||
std::vector<std::wstring> watchedDirectories;
|
||||
std::wstring shareMenuTitle;
|
||||
};
|
||||
static ContextMenuInfo FetchInfo();
|
||||
static void ShareObject(const std::wstring &path);
|
||||
struct ContextMenuInfo {
|
||||
std::vector<std::wstring> watchedDirectories;
|
||||
std::wstring shareMenuTitle;
|
||||
};
|
||||
static ContextMenuInfo FetchInfo();
|
||||
static void ShareObject(const std::wstring &path);
|
||||
};
|
||||
|
||||
#endif //ABSTRACTSOCKETHANDLER_H
|
||||
|
||||
@@ -30,27 +30,27 @@ extern long g_cDllRef;
|
||||
|
||||
|
||||
OCContextMenu::OCContextMenu(void)
|
||||
: m_cRef(1)
|
||||
, m_pszMenuText(L"&Share")
|
||||
, m_pszVerb("ocshare")
|
||||
, m_pwszVerb(L"ocshare")
|
||||
, m_pszVerbCanonicalName("OCShareViaOC")
|
||||
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
||||
, m_pszVerbHelpText("Share via ownCloud")
|
||||
, m_pwszVerbHelpText(L"Share via ownCloud")
|
||||
: m_cRef(1)
|
||||
, m_pszMenuText(L"&Share")
|
||||
, m_pszVerb("ocshare")
|
||||
, m_pwszVerb(L"ocshare")
|
||||
, m_pszVerbCanonicalName("OCShareViaOC")
|
||||
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
||||
, m_pszVerbHelpText("Share via ownCloud")
|
||||
, m_pwszVerbHelpText(L"Share via ownCloud")
|
||||
{
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
OCContextMenu::~OCContextMenu(void)
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
|
||||
void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
||||
{
|
||||
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
||||
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,30 +59,30 @@ void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
||||
// Query to the interface the component supported.
|
||||
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(OCContextMenu, IContextMenu),
|
||||
QITABENT(OCContextMenu, IShellExtInit),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(OCContextMenu, IContextMenu),
|
||||
QITABENT(OCContextMenu, IShellExtInit),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
// Increase the reference count for an interface on an object.
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
// Decrease the reference count for an interface on an object.
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return cRef;
|
||||
return cRef;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -92,40 +92,40 @@ IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
|
||||
// Initialize the context menu handler.
|
||||
IFACEMETHODIMP OCContextMenu::Initialize(
|
||||
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
||||
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
||||
{
|
||||
if (!pDataObj) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (!pDataObj) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stm;
|
||||
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stm;
|
||||
|
||||
if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) {
|
||||
// Get an HDROP handle.
|
||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||
if (hDrop) {
|
||||
// Ignore multi-selections
|
||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
if (nFiles == 1) {
|
||||
// Get the path of the file.
|
||||
if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) {
|
||||
// Get an HDROP handle.
|
||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||
if (hDrop) {
|
||||
// Ignore multi-selections
|
||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
if (nFiles == 1) {
|
||||
// Get the path of the file.
|
||||
if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUnlock(stm.hGlobal);
|
||||
}
|
||||
GlobalUnlock(stm.hGlobal);
|
||||
}
|
||||
|
||||
ReleaseStgMedium(&stm);
|
||||
}
|
||||
ReleaseStgMedium(&stm);
|
||||
}
|
||||
|
||||
// If any value other than S_OK is returned from the method, the context
|
||||
// menu item is not displayed.
|
||||
return hr;
|
||||
// If any value other than S_OK is returned from the method, the context
|
||||
// menu item is not displayed.
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -135,135 +135,136 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
||||
|
||||
void InsertSeperator(HMENU hMenu, UINT indexMenu)
|
||||
{
|
||||
// Add a separator.
|
||||
MENUITEMINFO sep = { sizeof(sep) };
|
||||
sep.fMask = MIIM_TYPE;
|
||||
sep.fType = MFT_SEPARATOR;
|
||||
InsertMenuItem(hMenu, indexMenu, TRUE, &sep);
|
||||
// Add a separator.
|
||||
MENUITEMINFO sep = { sizeof(sep) };
|
||||
sep.fMask = MIIM_TYPE;
|
||||
sep.fType = MFT_SEPARATOR;
|
||||
InsertMenuItem(hMenu, indexMenu, TRUE, &sep);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
|
||||
if (CMF_DEFAULTONLY & uFlags)
|
||||
{
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
|
||||
if (CMF_DEFAULTONLY & uFlags)
|
||||
{
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
|
||||
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
||||
bool skip = true;
|
||||
for (const std::wstring path : info.watchedDirectories) {
|
||||
if (StringUtil::begins_with(std::wstring(m_szSelectedFile), path)) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
||||
bool skip = true;
|
||||
size_t selectedFileLength = wcslen(m_szSelectedFile);
|
||||
for (const std::wstring path : info.watchedDirectories) {
|
||||
if (StringUtil::isDescendantOf(m_szSelectedFile, selectedFileLength, path)) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
if (skip) {
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
mii.fState = MFS_ENABLED;
|
||||
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
mii.fState = MFS_ENABLED;
|
||||
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
|
||||
|
||||
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
||||
// Set the code value to the offset of the largest command identifier
|
||||
// that was assigned, plus one (1).
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
||||
// Set the code value to the offset of the largest command identifier
|
||||
// that was assigned, plus one (1).
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
|
||||
// For the Unicode case, if the high-order word is not zero, the
|
||||
// command's verb string is in lpcmi->lpVerbW.
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
||||
{
|
||||
// Is the verb supported by this context menu extension?
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// For the Unicode case, if the high-order word is not zero, the
|
||||
// command's verb string is in lpcmi->lpVerbW.
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
||||
{
|
||||
// Is the verb supported by this context menu extension?
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// If the command cannot be identified through the verb string, then
|
||||
// check the identifier offset.
|
||||
else
|
||||
{
|
||||
// Is the command identifier offset supported by this context menu
|
||||
// extension?
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// If the command cannot be identified through the verb string, then
|
||||
// check the identifier offset.
|
||||
else
|
||||
{
|
||||
// Is the command identifier offset supported by this context menu
|
||||
// extension?
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
||||
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (idCommand == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
// Only useful for pre-Vista versions of Windows that have a
|
||||
// Status bar.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbHelpText);
|
||||
break;
|
||||
if (idCommand == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
// Only useful for pre-Vista versions of Windows that have a
|
||||
// Status bar.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbHelpText);
|
||||
break;
|
||||
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
// idCommand.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbCanonicalName);
|
||||
break;
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
// idCommand.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbCanonicalName);
|
||||
break;
|
||||
|
||||
default:
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
default:
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If the command (idCommand) is not supported by this context menu
|
||||
// extension handler, return E_INVALIDARG.
|
||||
// If the command (idCommand) is not supported by this context menu
|
||||
// extension handler, return E_INVALIDARG.
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -26,12 +26,12 @@ extern long g_cDllRef;
|
||||
|
||||
OCContextMenuFactory::OCContextMenuFactory() : m_cRef(1)
|
||||
{
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
OCContextMenuFactory::~OCContextMenuFactory()
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,22 +39,22 @@ OCContextMenuFactory::~OCContextMenuFactory()
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] = { QITABENT(OCContextMenuFactory, IClassFactory), { 0 }, };
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
static const QITAB qit[] = { QITABENT(OCContextMenuFactory, IClassFactory), { 0 }, };
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenuFactory::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenuFactory::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,30 +62,30 @@ IFACEMETHODIMP_(ULONG) OCContextMenuFactory::Release()
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hr = CLASS_E_NOAGGREGATION;
|
||||
HRESULT hr = CLASS_E_NOAGGREGATION;
|
||||
|
||||
// pUnkOuter is used for aggregation. We do not support it in the sample.
|
||||
if (pUnkOuter == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
// pUnkOuter is used for aggregation. We do not support it in the sample.
|
||||
if (pUnkOuter == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
// Create the COM component.
|
||||
OCContextMenu *pExt = new (std::nothrow) OCContextMenu();
|
||||
if (pExt) {
|
||||
// Query the specified interface.
|
||||
hr = pExt->QueryInterface(riid, ppv);
|
||||
pExt->Release();
|
||||
}
|
||||
}
|
||||
// Create the COM component.
|
||||
OCContextMenu *pExt = new (std::nothrow) OCContextMenu();
|
||||
if (pExt) {
|
||||
// Query the specified interface.
|
||||
hr = pExt->QueryInterface(riid, ppv);
|
||||
pExt->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::LockServer(BOOL fLock)
|
||||
{
|
||||
if (fLock) {
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
} else {
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
return S_OK;
|
||||
if (fLock) {
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
} else {
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -23,20 +23,20 @@
|
||||
class OCContextMenuFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
OCContextMenuFactory();
|
||||
OCContextMenuFactory();
|
||||
|
||||
private:
|
||||
~OCContextMenuFactory();
|
||||
long m_cRef;
|
||||
~OCContextMenuFactory();
|
||||
long m_cRef;
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENUFACTORY_H
|
||||
@@ -23,196 +23,196 @@ namespace {
|
||||
|
||||
HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData)
|
||||
{
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
// Creates the specified registry key. If the key already exists, the
|
||||
// function opens it.
|
||||
hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL));
|
||||
// Creates the specified registry key. If the key already exists, the
|
||||
// function opens it.
|
||||
hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (pszData != NULL)
|
||||
{
|
||||
// Set the specified value of the key.
|
||||
DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
|
||||
REG_SZ, reinterpret_cast<const BYTE *>(pszData), cbData));
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (pszData != NULL)
|
||||
{
|
||||
// Set the specified value of the key.
|
||||
DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
|
||||
REG_SZ, reinterpret_cast<const BYTE *>(pszData), cbData));
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData)
|
||||
{
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
// Try to open the specified registry key.
|
||||
hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
KEY_READ, &hKey));
|
||||
// Try to open the specified registry key.
|
||||
hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
KEY_READ, &hKey));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Get the data for the specified value name.
|
||||
hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
|
||||
NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Get the data for the specified value name.
|
||||
hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
|
||||
NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
|
||||
{
|
||||
if (pszModule == NULL || pszThreadModel == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszModule == NULL || pszThreadModel == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Create the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
|
||||
// Create the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
|
||||
|
||||
// Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"CLSID\\%s\\InprocServer32", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the InprocServer32 key to the
|
||||
// path of the COM module.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the threading model of the component.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey,
|
||||
L"ThreadingModel", pszThreadModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"CLSID\\%s\\InprocServer32", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the InprocServer32 key to the
|
||||
// path of the COM module.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the threading model of the component.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey,
|
||||
L"ThreadingModel", pszThreadModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Delete the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
// Delete the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT OCContextMenuRegHandler::RegisterShellExtContextMenuHandler(
|
||||
PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
|
||||
PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
|
||||
{
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the key.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, szCLSID);
|
||||
}
|
||||
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the key.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, szCLSID);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(
|
||||
PCWSTR pszFileType, PCWSTR pszFriendlyName)
|
||||
PCWSTR pszFileType, PCWSTR pszFriendlyName)
|
||||
{
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
// Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
@@ -23,16 +23,16 @@
|
||||
class __declspec(dllexport) OCContextMenuRegHandler
|
||||
{
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
|
||||
static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
|
||||
static HRESULT UnregisterInprocServer(const CLSID& clsid);
|
||||
static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
|
||||
static HRESULT UnregisterInprocServer(const CLSID& clsid);
|
||||
|
||||
static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
|
||||
static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName);
|
||||
static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
|
||||
static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName);
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENUREGHANDLER_H
|
||||
@@ -23,142 +23,142 @@ long dllReferenceCount = 0;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
instanceHandle = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
instanceHandle = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT CreateFactory(REFIID riid, void **ppv, int state)
|
||||
{
|
||||
HRESULT hResult = E_OUTOFMEMORY;
|
||||
HRESULT hResult = E_OUTOFMEMORY;
|
||||
|
||||
OCOverlayFactory* ocOverlayFactory = new OCOverlayFactory(state);
|
||||
OCOverlayFactory* ocOverlayFactory = new OCOverlayFactory(state);
|
||||
|
||||
if (ocOverlayFactory) {
|
||||
hResult = ocOverlayFactory->QueryInterface(riid, ppv);
|
||||
ocOverlayFactory->Release();
|
||||
}
|
||||
return hResult;
|
||||
if (ocOverlayFactory) {
|
||||
hResult = ocOverlayFactory->QueryInterface(riid, ppv);
|
||||
ocOverlayFactory->Release();
|
||||
}
|
||||
return hResult;
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = CLASS_E_CLASSNOTAVAILABLE;
|
||||
GUID guid;
|
||||
GUID guid;
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); }
|
||||
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return dllReferenceCount > 0 ? S_FALSE : S_OK;
|
||||
|
||||
return S_FALSE;
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT RegisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr, PCWSTR szModule)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
GUID guid;
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
GUID guid;
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_GENERIC_NAME, guid);
|
||||
hResult = OCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_GENERIC_NAME, guid);
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr);
|
||||
hResult = OCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT UnregisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
GUID guid;
|
||||
HRESULT hResult = S_OK;
|
||||
GUID guid;
|
||||
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::UnregisterCOMObject(guid);
|
||||
hResult = OCOverlayRegistrationHandler::UnregisterCOMObject(guid);
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr);
|
||||
hResult = OCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT _stdcall DllRegisterServer(void)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
wchar_t szModule[MAX_PATH];
|
||||
wchar_t szModule[MAX_PATH];
|
||||
|
||||
if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) {
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) {
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
|
||||
// Unregister any obsolete CLSID when we register here
|
||||
// Those CLSID were removed in 2.1, but we need to make sure to prevent any previous version
|
||||
// of the extension on the system from loading at the same time as a new version to avoid crashing explorer.
|
||||
UnregisterCLSID(OVERLAY_GUID_ERROR_SHARED, OVERLAY_NAME_ERROR_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_SYNC_SHARED, OVERLAY_NAME_SYNC_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_WARNING_SHARED, OVERLAY_NAME_WARNING_SHARED);
|
||||
// Unregister any obsolete CLSID when we register here
|
||||
// Those CLSID were removed in 2.1, but we need to make sure to prevent any previous version
|
||||
// of the extension on the system from loading at the same time as a new version to avoid crashing explorer.
|
||||
UnregisterCLSID(OVERLAY_GUID_ERROR_SHARED, OVERLAY_NAME_ERROR_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_SYNC_SHARED, OVERLAY_NAME_SYNC_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_WARNING_SHARED, OVERLAY_NAME_WARNING_SHARED);
|
||||
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule);
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer(void)
|
||||
@@ -167,21 +167,21 @@ STDAPI DllUnregisterServer(void)
|
||||
|
||||
wchar_t szModule[MAX_PATH];
|
||||
|
||||
if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0)
|
||||
if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0)
|
||||
{
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING);
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING);
|
||||
|
||||
return hResult;
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#include "OCContextMenu.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#define IDM_SHARE 0
|
||||
|
||||
OCContextMenu::OCContextMenu()
|
||||
: m_pwszVerb(0)
|
||||
, m_referenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OCContextMenu::~OCContextMenu()
|
||||
{
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_referenceCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_referenceCount);
|
||||
if (0 == cRef)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
return cRef;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IContextMenu, riid))
|
||||
{
|
||||
*ppv = static_cast<IContextMenu *>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_NOINTERFACE;
|
||||
*ppv = NULL;
|
||||
}
|
||||
|
||||
if (*ppv)
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (idCmd == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"Shares file or directory with ownCloud");
|
||||
break;
|
||||
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller
|
||||
// to discover the canonical name for the verb that is passed in
|
||||
// through idCommand.
|
||||
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"ownCloudShare");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
|
||||
(pici->fMask & CMIC_MASK_UNICODE))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW))
|
||||
{
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW, m_pwszVerb))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOWORD(pici->lpVerb) != IDM_SHARE) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
MessageBox(pici->hwnd,
|
||||
L"ownCloud was here",
|
||||
L"ownCloud was here",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!(CMF_DEFAULTONLY & uFlags))
|
||||
{
|
||||
InsertMenu(hMenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHARE, L"&Share with ownCloud");
|
||||
}
|
||||
hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"ownCloudShare");
|
||||
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef OCCONTEXTMENU_H
|
||||
#define OCCONTEXTMENU_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShObjIdl.h"
|
||||
#include "memory"
|
||||
|
||||
class OCContextMenu :public IContextMenu
|
||||
{
|
||||
public:
|
||||
OCContextMenu();
|
||||
~OCContextMenu();
|
||||
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
|
||||
IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
|
||||
IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
|
||||
IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
||||
private:
|
||||
TCHAR* m_pwszVerb;
|
||||
long m_referenceCount;
|
||||
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENU_H
|
||||
@@ -45,19 +45,19 @@ unique_ptr<RemotePathChecker> s_instance;
|
||||
|
||||
RemotePathChecker *getGlobalChecker()
|
||||
{
|
||||
// On Vista we'll run into issue #2680 if we try to create the thread+pipe connection
|
||||
// on any DllGetClassObject of our registered classes.
|
||||
// Work around the issue by creating the static RemotePathChecker only once actually needed.
|
||||
static once_flag s_onceFlag;
|
||||
call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); });
|
||||
// On Vista we'll run into issue #2680 if we try to create the thread+pipe connection
|
||||
// on any DllGetClassObject of our registered classes.
|
||||
// Work around the issue by creating the static RemotePathChecker only once actually needed.
|
||||
static once_flag s_onceFlag;
|
||||
call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); });
|
||||
|
||||
return s_instance.get();
|
||||
return s_instance.get();
|
||||
}
|
||||
|
||||
}
|
||||
OCOverlay::OCOverlay(int state)
|
||||
: _referenceCount(1)
|
||||
, _state(state)
|
||||
: _referenceCount(1)
|
||||
, _state(state)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ IFACEMETHODIMP OCOverlay::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -106,80 +106,65 @@ IFACEMETHODIMP_(ULONG) OCOverlay::Release()
|
||||
|
||||
IFACEMETHODIMP OCOverlay::GetPriority(int *pPriority)
|
||||
{
|
||||
// this defines which handler has prededence, so
|
||||
// we order this in terms of likelyhood
|
||||
switch (_state) {
|
||||
case State_OK:
|
||||
*pPriority = 0; break;
|
||||
case State_OKShared:
|
||||
*pPriority = 1; break;
|
||||
case State_Warning:
|
||||
*pPriority = 2; break;
|
||||
case State_Sync:
|
||||
*pPriority = 3; break;
|
||||
case State_Error:
|
||||
*pPriority = 4; break;
|
||||
default:
|
||||
*pPriority = 5; break;
|
||||
}
|
||||
// this defines which handler has prededence, so
|
||||
// we order this in terms of likelyhood
|
||||
switch (_state) {
|
||||
case State_OK:
|
||||
*pPriority = 0; break;
|
||||
case State_OKShared:
|
||||
*pPriority = 1; break;
|
||||
case State_Warning:
|
||||
*pPriority = 2; break;
|
||||
case State_Sync:
|
||||
*pPriority = 3; break;
|
||||
case State_Error:
|
||||
*pPriority = 4; break;
|
||||
default:
|
||||
*pPriority = 5; break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||
{
|
||||
RemotePathChecker* checker = getGlobalChecker();
|
||||
auto watchedDirectories = checker->WatchedDirectories();
|
||||
RemotePathChecker* checker = getGlobalChecker();
|
||||
std::shared_ptr<const std::vector<std::wstring>> watchedDirectories = checker->WatchedDirectories();
|
||||
|
||||
wstring wpath(pwszPath);
|
||||
wpath.append(L"\\");
|
||||
vector<wstring>::iterator it;
|
||||
bool watched = false;
|
||||
for (it = watchedDirectories.begin(); it != watchedDirectories.end(); ++it) {
|
||||
if (StringUtil::begins_with(wpath, *it)) {
|
||||
watched = true;
|
||||
}
|
||||
}
|
||||
if (watchedDirectories->empty()) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
if (!watched) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
bool watched = false;
|
||||
size_t pathLength = wcslen(pwszPath);
|
||||
for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) {
|
||||
if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) {
|
||||
watched = true;
|
||||
}
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
if (!checker->IsMonitoredPath(pwszPath, &state)) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0);
|
||||
if (!watched) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
if (!checker->IsMonitoredPath(pwszPath, &state)) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)
|
||||
{
|
||||
*pIndex = 0;
|
||||
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
|
||||
*pIndex = _state;
|
||||
*pIndex = 0;
|
||||
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
|
||||
*pIndex = _state;
|
||||
|
||||
if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) {
|
||||
HRESULT hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl;
|
||||
return hResult;
|
||||
}
|
||||
if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) {
|
||||
HRESULT hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
bool OCOverlay::_IsOverlaysEnabled()
|
||||
{
|
||||
//int enable;
|
||||
bool success = false;
|
||||
|
||||
//if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_ENABLE_OVERLAY, &enable))
|
||||
//{
|
||||
// if(enable) {
|
||||
// success = true;
|
||||
// }
|
||||
//}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,22 +21,21 @@ class OCOverlay : public IShellIconOverlayIdentifier
|
||||
|
||||
{
|
||||
public:
|
||||
OCOverlay(int state);
|
||||
OCOverlay(int state);
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
|
||||
IFACEMETHODIMP GetPriority(int *pPriority);
|
||||
IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
|
||||
IFACEMETHODIMP GetPriority(int *pPriority);
|
||||
IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
protected:
|
||||
~OCOverlay();
|
||||
|
||||
private:
|
||||
bool _IsOverlaysEnabled();
|
||||
long _referenceCount;
|
||||
int _state;
|
||||
int _state;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
extern long dllReferenceCount;
|
||||
|
||||
OCOverlayFactory::OCOverlayFactory(int state)
|
||||
: _referenceCount(1), _state(state)
|
||||
: _referenceCount(1), _state(state)
|
||||
{
|
||||
InterlockedIncrement(&dllReferenceCount);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ OCOverlayFactory::~OCOverlayFactory()
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
if (IsEqualIID(IID_IUnknown, riid) ||
|
||||
IsEqualIID(IID_IClassFactory, riid))
|
||||
@@ -66,20 +66,20 @@ IFACEMETHODIMP_(ULONG) OCOverlayFactory::Release()
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::CreateInstance(
|
||||
IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = CLASS_E_NOAGGREGATION;
|
||||
HRESULT hResult = CLASS_E_NOAGGREGATION;
|
||||
|
||||
if (pUnkOuter != NULL) { return hResult; }
|
||||
|
||||
hResult = E_OUTOFMEMORY;
|
||||
hResult = E_OUTOFMEMORY;
|
||||
OCOverlay *lrOverlay = new (std::nothrow) OCOverlay(_state);
|
||||
if (!lrOverlay) { return hResult; }
|
||||
if (!lrOverlay) { return hResult; }
|
||||
|
||||
hResult = lrOverlay->QueryInterface(riid, ppv);
|
||||
lrOverlay->Release();
|
||||
lrOverlay->Release();
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::LockServer(BOOL fLock)
|
||||
|
||||
@@ -18,20 +18,20 @@
|
||||
#pragma once
|
||||
|
||||
enum State {
|
||||
State_Error = 0,
|
||||
State_OK, State_OKShared,
|
||||
State_Sync,
|
||||
State_Warning
|
||||
State_Error = 0,
|
||||
State_OK, State_OKShared,
|
||||
State_Sync,
|
||||
State_Warning
|
||||
};
|
||||
|
||||
class OCOverlayFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
OCOverlayFactory(int state);
|
||||
OCOverlayFactory(int state);
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
@@ -40,7 +40,7 @@ protected:
|
||||
|
||||
private:
|
||||
long _referenceCount;
|
||||
int _state;
|
||||
int _state;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -23,52 +23,52 @@ using namespace std;
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::MakeRegistryEntries(const CLSID& clsid, PCWSTR friendlyName)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
// the key may not exist yet
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &shellOverlayKey, NULL));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey);
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
}
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
// the key may not exist yet
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &shellOverlayKey, NULL));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey);
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
}
|
||||
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &syncExOverlayKey, NULL));
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &syncExOverlayKey, NULL));
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
LPCTSTR value = stringCLSID;
|
||||
hResult = RegSetValueEx(syncExOverlayKey, NULL, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR)));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
LPCTSTR value = stringCLSID;
|
||||
hResult = RegSetValueEx(syncExOverlayKey, NULL, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR)));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::RemoveRegistryEntries(PCWSTR friendlyName)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey));
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey));
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid)
|
||||
@@ -79,45 +79,45 @@ HRESULT OCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWST
|
||||
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &clsidKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &clsidKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, NULL, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName)));
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, NULL, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName)));
|
||||
|
||||
HKEY inprocessKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &inprocessKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY inprocessKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &inprocessKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, NULL, REG_SZ, modulePath, (DWORD) wcslen(modulePath)));
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, NULL, REG_SZ, modulePath, (DWORD) wcslen(modulePath)));
|
||||
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_THREADING, 0, REG_SZ, (LPBYTE)REGISTRY_APARTMENT, (DWORD)((wcslen(REGISTRY_APARTMENT)+1) * sizeof(TCHAR))));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_VERSION, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR)));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_VERSION, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR)));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid)
|
||||
@@ -125,28 +125,28 @@ HRESULT OCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid)
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
class __declspec(dllexport) OCOverlayRegistrationHandler
|
||||
{
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -13,38 +13,38 @@
|
||||
*/
|
||||
|
||||
|
||||
#define OVERLAY_GUID_ERROR L"{0960F090-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR_SHARED L"{0960F091-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK L"{0960F092-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK_SHARED L"{0960F093-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC L"{0960F094-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC_SHARED L"{0960F095-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING L"{0960F096-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR L"{0960F090-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR_SHARED L"{0960F091-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK L"{0960F092-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK_SHARED L"{0960F093-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC L"{0960F094-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC_SHARED L"{0960F095-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING L"{0960F096-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING_SHARED L"{0960F097-F328-48A3-B746-276B1E3C3722}"
|
||||
|
||||
#define OVERLAY_GENERIC_NAME L"OC Overlay Handler"
|
||||
|
||||
// two spaces to put us ahead of the competition :/
|
||||
#define OVERLAY_NAME_ERROR L" OCError"
|
||||
#define OVERLAY_NAME_ERROR_SHARED L" OCErrorShared"
|
||||
#define OVERLAY_NAME_OK L" OCOK"
|
||||
#define OVERLAY_NAME_OK_SHARED L" OCOKShared"
|
||||
#define OVERLAY_NAME_SYNC L" OCSync"
|
||||
#define OVERLAY_NAME_SYNC_SHARED L" OCSyncShared"
|
||||
#define OVERLAY_NAME_WARNING L" OCWarning"
|
||||
#define OVERLAY_NAME_WARNING_SHARED L" OCWarningShared"
|
||||
#define OVERLAY_NAME_ERROR L" OCError"
|
||||
#define OVERLAY_NAME_ERROR_SHARED L" OCErrorShared"
|
||||
#define OVERLAY_NAME_OK L" OCOK"
|
||||
#define OVERLAY_NAME_OK_SHARED L" OCOKShared"
|
||||
#define OVERLAY_NAME_SYNC L" OCSync"
|
||||
#define OVERLAY_NAME_SYNC_SHARED L" OCSyncShared"
|
||||
#define OVERLAY_NAME_WARNING L" OCWarning"
|
||||
#define OVERLAY_NAME_WARNING_SHARED L" OCWarningShared"
|
||||
|
||||
#define REGISTRY_OVERLAY_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers"
|
||||
#define REGISTRY_CLSID L"CLSID"
|
||||
#define REGISTRY_IN_PROCESS L"InprocServer32"
|
||||
#define REGISTRY_THREADING L"ThreadingModel"
|
||||
#define REGISTRY_APARTMENT L"Apartment"
|
||||
#define REGISTRY_VERSION L"Version"
|
||||
#define REGISTRY_VERSION_NUMBER L"1.0"
|
||||
#define REGISTRY_OVERLAY_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers"
|
||||
#define REGISTRY_CLSID L"CLSID"
|
||||
#define REGISTRY_IN_PROCESS L"InprocServer32"
|
||||
#define REGISTRY_THREADING L"ThreadingModel"
|
||||
#define REGISTRY_APARTMENT L"Apartment"
|
||||
#define REGISTRY_VERSION L"Version"
|
||||
#define REGISTRY_VERSION_NUMBER L"1.0"
|
||||
|
||||
//Registry values for running
|
||||
#define REGISTRY_ENABLE_OVERLAY L"EnableOverlay"
|
||||
#define REGISTRY_ENABLE_OVERLAY L"EnableOverlay"
|
||||
|
||||
#define GET_FILE_OVERLAY_ID L"getFileIconId"
|
||||
#define GET_FILE_OVERLAY_ID L"getFileIconId"
|
||||
|
||||
#define PORT 34001
|
||||
#define PORT 34001
|
||||
@@ -31,23 +31,23 @@ using namespace std;
|
||||
namespace {
|
||||
|
||||
std::wstring getUserName() {
|
||||
DWORD len = DEFAULT_BUFLEN;
|
||||
TCHAR buf[DEFAULT_BUFLEN];
|
||||
if (GetUserName(buf, &len)) {
|
||||
return std::wstring(&buf[0], len);
|
||||
} else {
|
||||
return std::wstring();
|
||||
}
|
||||
DWORD len = DEFAULT_BUFLEN;
|
||||
TCHAR buf[DEFAULT_BUFLEN];
|
||||
if (GetUserName(buf, &len)) {
|
||||
return std::wstring(&buf[0], len);
|
||||
} else {
|
||||
return std::wstring();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::wstring CommunicationSocket::DefaultPipePath()
|
||||
{
|
||||
auto pipename = std::wstring(L"\\\\.\\pipe\\");
|
||||
pipename += L"ownCloud-";
|
||||
pipename += getUserName();
|
||||
return pipename;
|
||||
auto pipename = std::wstring(L"\\\\.\\pipe\\");
|
||||
pipename += L"ownCloud-";
|
||||
pipename += getUserName();
|
||||
return pipename;
|
||||
}
|
||||
|
||||
CommunicationSocket::CommunicationSocket()
|
||||
@@ -57,23 +57,23 @@ CommunicationSocket::CommunicationSocket()
|
||||
|
||||
CommunicationSocket::~CommunicationSocket()
|
||||
{
|
||||
Close();
|
||||
Close();
|
||||
}
|
||||
|
||||
bool CommunicationSocket::Close()
|
||||
{
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
CloseHandle(_pipe);
|
||||
_pipe = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
CloseHandle(_pipe);
|
||||
_pipe = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CommunicationSocket::Connect(const std::wstring &pipename)
|
||||
{
|
||||
_pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
_pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
@@ -84,7 +84,7 @@ bool CommunicationSocket::Connect(const std::wstring &pipename)
|
||||
|
||||
bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
{
|
||||
auto utf8_msg = StringUtil::toUtf8(message);
|
||||
auto utf8_msg = StringUtil::toUtf8(message);
|
||||
|
||||
DWORD numBytesWritten = 0;
|
||||
auto result = WriteFile( _pipe, utf8_msg.c_str(), DWORD(utf8_msg.size()), &numBytesWritten, NULL);
|
||||
@@ -92,7 +92,7 @@ bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
const_cast<CommunicationSocket*>(this)->Close();
|
||||
const_cast<CommunicationSocket*>(this)->Close();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -100,9 +100,9 @@ bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
|
||||
bool CommunicationSocket::ReadLine(wstring* response)
|
||||
{
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
response->clear();
|
||||
|
||||
@@ -110,7 +110,7 @@ bool CommunicationSocket::ReadLine(wstring* response)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (true) {
|
||||
int lbPos = 0;
|
||||
auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n');
|
||||
if (it != _buffer.end()) {
|
||||
@@ -121,24 +121,24 @@ bool CommunicationSocket::ReadLine(wstring* response)
|
||||
|
||||
std::array<char, 128> resp_utf8;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD totalBytesAvailable = 0;
|
||||
DWORD totalBytesAvailable = 0;
|
||||
|
||||
if (!PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (totalBytesAvailable == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (totalBytesAvailable == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL)) {
|
||||
if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (numBytesRead <= 0) {
|
||||
return false;
|
||||
}
|
||||
_buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead);
|
||||
_buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,22 +26,22 @@
|
||||
class __declspec(dllexport) CommunicationSocket
|
||||
{
|
||||
public:
|
||||
static std::wstring DefaultPipePath();
|
||||
static std::wstring DefaultPipePath();
|
||||
|
||||
CommunicationSocket();
|
||||
~CommunicationSocket();
|
||||
CommunicationSocket();
|
||||
~CommunicationSocket();
|
||||
|
||||
bool Connect(const std::wstring& pipename);
|
||||
bool Close();
|
||||
bool Connect(const std::wstring& pipename);
|
||||
bool Close();
|
||||
|
||||
bool SendMsg(const wchar_t*) const;
|
||||
bool ReadLine(std::wstring*);
|
||||
bool SendMsg(const wchar_t*) const;
|
||||
bool ReadLine(std::wstring*);
|
||||
|
||||
HANDLE Event() { return _pipe; }
|
||||
|
||||
private:
|
||||
HANDLE _pipe;
|
||||
std::vector<char> _buffer;
|
||||
private:
|
||||
HANDLE _pipe;
|
||||
std::vector<char> _buffer;
|
||||
bool _connected;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,65 +22,65 @@ using namespace std;
|
||||
|
||||
bool FileUtil::IsChildFile(const wchar_t* rootFolder, vector<wstring>* files)
|
||||
{
|
||||
for(vector<wstring>::iterator it = files->begin(); it != files->end(); it++)
|
||||
{
|
||||
wstring file = *it;
|
||||
for(vector<wstring>::iterator it = files->begin(); it != files->end(); it++)
|
||||
{
|
||||
wstring file = *it;
|
||||
|
||||
size_t found = file.find(rootFolder);
|
||||
size_t found = file.find(rootFolder);
|
||||
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFile(const wchar_t* rootFolder, const wchar_t* file)
|
||||
{
|
||||
wstring* f = new wstring(file);
|
||||
wstring* f = new wstring(file);
|
||||
|
||||
size_t found = f->find(rootFolder);
|
||||
size_t found = f->find(rootFolder);
|
||||
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFileOfRoot(std::vector<std::wstring>* files)
|
||||
{
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(IsChildFile(rootFolder->c_str(), files))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(IsChildFile(rootFolder->c_str(), files))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFileOfRoot(const wchar_t* filePath)
|
||||
{
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(FileUtil::IsChildFile(rootFolder->c_str(), filePath))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(FileUtil::IsChildFile(rootFolder->c_str(), filePath))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
}
|
||||
@@ -25,16 +25,16 @@
|
||||
class __declspec(dllexport) FileUtil
|
||||
{
|
||||
public:
|
||||
FileUtil();
|
||||
FileUtil();
|
||||
|
||||
~FileUtil();
|
||||
~FileUtil();
|
||||
|
||||
static bool IsChildFile(const wchar_t*, std::vector<std::wstring>*);
|
||||
static bool IsChildFile(const wchar_t*, const wchar_t*);
|
||||
static bool IsChildFileOfRoot(std::vector<std::wstring>*);
|
||||
static bool IsChildFileOfRoot(const wchar_t*);
|
||||
static bool IsChildFile(const wchar_t*, std::vector<std::wstring>*);
|
||||
static bool IsChildFile(const wchar_t*, const wchar_t*);
|
||||
static bool IsChildFileOfRoot(std::vector<std::wstring>*);
|
||||
static bool IsChildFileOfRoot(const wchar_t*);
|
||||
|
||||
private:
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -25,8 +25,8 @@ using namespace std;
|
||||
|
||||
OCMessage::OCMessage(void)
|
||||
{
|
||||
_command = new wstring();
|
||||
_value = new wstring();
|
||||
_command = new wstring();
|
||||
_value = new wstring();
|
||||
}
|
||||
|
||||
OCMessage::~OCMessage(void)
|
||||
@@ -35,40 +35,40 @@ OCMessage::~OCMessage(void)
|
||||
|
||||
bool OCMessage::InitFromMessage(const wstring* message)
|
||||
{
|
||||
if(message->length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(COMMAND, message, _command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(message->length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(COMMAND, message, _command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(VALUE, message, _value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ParserUtil::GetItem(VALUE, message, _value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::wstring* OCMessage::GetCommand()
|
||||
{
|
||||
return _command;
|
||||
return _command;
|
||||
}
|
||||
|
||||
std::wstring* OCMessage::GetValue()
|
||||
{
|
||||
return _value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
void OCMessage::SetCommand(std::wstring* command)
|
||||
{
|
||||
_command = command;
|
||||
_command = command;
|
||||
}
|
||||
|
||||
void OCMessage::SetValue(std::wstring* value)
|
||||
{
|
||||
_value = value;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
@@ -23,20 +23,20 @@ class __declspec(dllexport) OCMessage
|
||||
{
|
||||
public:
|
||||
OCMessage(void);
|
||||
~OCMessage(void);
|
||||
~OCMessage(void);
|
||||
|
||||
bool InitFromMessage(const std::wstring*);
|
||||
bool InitFromMessage(const std::wstring*);
|
||||
|
||||
std::wstring* GetCommand();
|
||||
std::wstring* GetValue();
|
||||
std::wstring* GetCommand();
|
||||
std::wstring* GetValue();
|
||||
|
||||
void SetCommand(std::wstring*);
|
||||
void SetValue(std::wstring*);
|
||||
void SetCommand(std::wstring*);
|
||||
void SetValue(std::wstring*);
|
||||
|
||||
private:
|
||||
|
||||
std::wstring* _command;
|
||||
std::wstring* _value;
|
||||
std::wstring* _value;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -21,369 +21,369 @@ using namespace std;
|
||||
|
||||
bool ParserUtil::GetItem(const wchar_t* item, const wstring* message, wstring* result)
|
||||
{
|
||||
size_t start = message->find(item, 0);
|
||||
size_t start = message->find(item, 0);
|
||||
|
||||
if(start == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(start == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t end = message->find(COLON, start);
|
||||
size_t end = message->find(COLON, start);
|
||||
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Move to next character after :
|
||||
end += 1;
|
||||
//Move to next character after :
|
||||
end += 1;
|
||||
|
||||
wchar_t c = message->at(end);
|
||||
wchar_t c = message->at(end);
|
||||
|
||||
//Move to the next character, which is the start of the value
|
||||
end += 1;
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return GetList(end - 1, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetValue(end, message, result);
|
||||
}
|
||||
//Move to the next character, which is the start of the value
|
||||
end += 1;
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return GetList(end - 1, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetValue(end, message, result);
|
||||
}
|
||||
}
|
||||
|
||||
bool ParserUtil::GetList(size_t start, const wstring* message, wstring* result)
|
||||
{
|
||||
size_t end = start + 1;
|
||||
size_t end = start + 1;
|
||||
|
||||
int openBraceCount = 1;
|
||||
int openBraceCount = 1;
|
||||
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_BRACE, end);
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_BRACE, end);
|
||||
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
|
||||
return GetString(start, end, message, result);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
|
||||
size_t ParserUtil::GetNextStringItemInList(const wstring* message, size_t start, wstring* result)
|
||||
{
|
||||
size_t end = string::npos;
|
||||
size_t commaLocation = message->find(COMMA, start);
|
||||
size_t end = string::npos;
|
||||
size_t commaLocation = message->find(COMMA, start);
|
||||
|
||||
if(commaLocation == string::npos)
|
||||
{
|
||||
end = message->find(CLOSE_BRACE, start);
|
||||
if(end == string::npos)
|
||||
{
|
||||
end = message->length();
|
||||
}
|
||||
else
|
||||
{
|
||||
end = end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
end = commaLocation - 1;
|
||||
}
|
||||
if(commaLocation == string::npos)
|
||||
{
|
||||
end = message->find(CLOSE_BRACE, start);
|
||||
if(end == string::npos)
|
||||
{
|
||||
end = message->length();
|
||||
}
|
||||
else
|
||||
{
|
||||
end = end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
end = commaLocation - 1;
|
||||
}
|
||||
|
||||
if(!GetString(start + 2, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
if(!GetString(start + 2, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
return end + 2;
|
||||
return end + 2;
|
||||
}
|
||||
|
||||
size_t ParserUtil::GetNextOCItemInList(const wstring* message, size_t start, wstring* result)
|
||||
{
|
||||
size_t end = message->find(OPEN_CURLY_BRACE, start) + 1;
|
||||
size_t end = message->find(OPEN_CURLY_BRACE, start) + 1;
|
||||
|
||||
int openBraceCount = 1;
|
||||
int openBraceCount = 1;
|
||||
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_CURLY_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_CURLY_BRACE, end);
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_CURLY_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_CURLY_BRACE, end);
|
||||
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
}
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
size_t length = end - start;
|
||||
|
||||
if(!GetString(start, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
if(!GetString(start, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
return end;
|
||||
return end;
|
||||
}
|
||||
|
||||
bool ParserUtil::GetValue(size_t start, const wstring* message, wstring* result)
|
||||
{
|
||||
if(message->at(start - 1) == '\"')
|
||||
{
|
||||
size_t end = message->find(QUOTE, start);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = start - 1;
|
||||
if(message->at(start - 1) == '\"')
|
||||
{
|
||||
size_t end = message->find(QUOTE, start);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = start - 1;
|
||||
|
||||
size_t end = message->find(COMMA, start);
|
||||
|
||||
result->append(message->substr(start, end-start));
|
||||
}
|
||||
size_t end = message->find(COMMA, start);
|
||||
|
||||
result->append(message->substr(start, end-start));
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::GetString(size_t start, size_t end, const wstring* message, wstring* result)
|
||||
{
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
size_t length = end - start;
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
result->append(message->substr(start, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
result->append(L"");
|
||||
}
|
||||
if(length > 0)
|
||||
{
|
||||
result->append(message->substr(start, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
result->append(L"");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::IsList(wstring* message)
|
||||
{
|
||||
wchar_t c = message->at(0);
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
wchar_t c = message->at(0);
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseJsonList(wstring* message, vector<wstring*>* items)
|
||||
{
|
||||
|
||||
size_t currentLocation = message->find(OPEN_BRACE, 0);
|
||||
size_t currentLocation = message->find(OPEN_BRACE, 0);
|
||||
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
|
||||
currentLocation = ParserUtil::GetNextStringItemInList(message, currentLocation, item);
|
||||
currentLocation = ParserUtil::GetNextStringItemInList(message, currentLocation, item);
|
||||
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
items->push_back(item);
|
||||
}
|
||||
items->push_back(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseOCList(wstring* message, vector<wstring*>* items)
|
||||
{
|
||||
|
||||
size_t currentLocation = message->find(OPEN_CURLY_BRACE, 0);
|
||||
size_t currentLocation = message->find(OPEN_CURLY_BRACE, 0);
|
||||
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
|
||||
currentLocation = ParserUtil::GetNextOCItemInList(message, currentLocation, item);
|
||||
currentLocation = ParserUtil::GetNextOCItemInList(message, currentLocation, item);
|
||||
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
items->push_back(item);
|
||||
}
|
||||
items->push_back(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseOCMessageList(wstring* message, vector<OCMessage*>* messages)
|
||||
{
|
||||
vector<wstring*>* items = new vector<wstring*>();
|
||||
vector<wstring*>* items = new vector<wstring*>();
|
||||
|
||||
if(!ParseOCList(message, items))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ParseOCList(message, items))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(vector<wstring*>::iterator it = items->begin(); it != items->end(); it++)
|
||||
{
|
||||
wstring* temp = *it;
|
||||
for(vector<wstring*>::iterator it = items->begin(); it != items->end(); it++)
|
||||
{
|
||||
wstring* temp = *it;
|
||||
|
||||
OCMessage* message = new OCMessage();
|
||||
message->InitFromMessage(temp);
|
||||
OCMessage* message = new OCMessage();
|
||||
message->InitFromMessage(temp);
|
||||
|
||||
messages->push_back(message);
|
||||
}
|
||||
messages->push_back(message);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeList(std::vector<std::wstring>* list, std::wstring* result, bool escapeQuotes)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_BRACE);
|
||||
result->append(OPEN_BRACE);
|
||||
|
||||
for(vector<wstring>::iterator it = list->begin(); it != list->end(); it++)
|
||||
{
|
||||
wstring value = *it;
|
||||
for(vector<wstring>::iterator it = list->begin(); it != list->end(); it++)
|
||||
{
|
||||
wstring value = *it;
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(value.c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(value.c_str());
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
}
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
}
|
||||
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
|
||||
result->append(CLOSE_BRACE);
|
||||
result->append(CLOSE_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeMessage(std::map<std::wstring*, std::wstring*>* arguments, std::wstring* result, bool escapeQuotes)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
|
||||
for(map<wstring*, wstring*>::iterator it = arguments->begin(); it != arguments->end(); it++)
|
||||
{
|
||||
wstring key = *it->first;
|
||||
wstring value = *it->second;
|
||||
for(map<wstring*, wstring*>::iterator it = arguments->begin(); it != arguments->end(); it++)
|
||||
{
|
||||
wstring key = *it->first;
|
||||
wstring value = *it->second;
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(key.c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(key.c_str());
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COLON);
|
||||
result->append(value.c_str());
|
||||
result->append(COMMA);
|
||||
}
|
||||
result->append(QUOTE);
|
||||
result->append(COLON);
|
||||
result->append(value.c_str());
|
||||
result->append(COMMA);
|
||||
}
|
||||
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeMessage(OCMessage* OCMessage, std::wstring* result)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COMMAND);
|
||||
result->append(QUOTE);
|
||||
result->append(QUOTE);
|
||||
result->append(COMMAND);
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COLON);
|
||||
result->append(COLON);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(OCMessage->GetCommand()->c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(QUOTE);
|
||||
result->append(OCMessage->GetCommand()->c_str());
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COMMA);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(VALUE);
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(VALUE);
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COLON);
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(OCMessage->GetValue()->c_str());
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
result->append(COLON);
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(OCMessage->GetValue()->c_str());
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,49 +22,49 @@ using namespace std;
|
||||
|
||||
bool RegistryUtil::ReadRegistry(const wchar_t* key, const wchar_t* name, int* result)
|
||||
{
|
||||
wstring* strResult = new wstring();
|
||||
wstring* strResult = new wstring();
|
||||
|
||||
if(!ReadRegistry(key, name, strResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ReadRegistry(key, name, strResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = stoi( strResult->c_str() );
|
||||
*result = stoi( strResult->c_str() );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegistryUtil::ReadRegistry(const wchar_t* key, const wchar_t* name, wstring* result)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HRESULT hResult;
|
||||
|
||||
HKEY rootKey = NULL;
|
||||
HKEY rootKey = NULL;
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, NULL, KEY_READ, &rootKey));
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, NULL, KEY_READ, &rootKey));
|
||||
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t value[SIZE];
|
||||
DWORD value_length = SIZE;
|
||||
|
||||
wchar_t value[SIZE];
|
||||
DWORD value_length = SIZE;
|
||||
|
||||
hResult = RegQueryValueEx(rootKey, (LPCWSTR)name, NULL, NULL, (LPBYTE)value, &value_length );
|
||||
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(value);
|
||||
result->append(value);
|
||||
|
||||
HRESULT hResult2 = RegCloseKey(rootKey);
|
||||
HRESULT hResult2 = RegCloseKey(rootKey);
|
||||
|
||||
if (!SUCCEEDED(hResult2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!SUCCEEDED(hResult2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
class __declspec(dllexport) RegistryUtil
|
||||
{
|
||||
public:
|
||||
RegistryUtil();
|
||||
RegistryUtil();
|
||||
|
||||
~RegistryUtil();
|
||||
~RegistryUtil();
|
||||
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, int*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, std::wstring*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, int*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, std::wstring*);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -40,7 +40,7 @@ void RemotePathChecker::workerThreadLoop()
|
||||
std::unordered_set<std::wstring> asked;
|
||||
|
||||
while(!_stop) {
|
||||
Sleep(50);
|
||||
Sleep(50);
|
||||
|
||||
if (!connected) {
|
||||
asked.clear();
|
||||
@@ -72,33 +72,42 @@ void RemotePathChecker::workerThreadLoop()
|
||||
|
||||
std::wstring response;
|
||||
while (!_stop && socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
_watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
||||
vectorCopy->push_back(responsePath);
|
||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
||||
|
||||
// We don't keep track of all files and can't know which file is currently visible
|
||||
// to the user, but at least reload the root dir so that any shortcut to the root
|
||||
// is updated without the user needing to refresh.
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
|
||||
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
_watchedDirectories.erase(
|
||||
std::remove(_watchedDirectories.begin(), _watchedDirectories.end(), responsePath),
|
||||
_watchedDirectories.end());
|
||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
||||
vectorCopy->erase(
|
||||
std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
|
||||
vectorCopy->end());
|
||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
||||
|
||||
vector<wstring> removedPaths;
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
// Remove any item from the cache
|
||||
for (auto it = _cache.begin(); it != _cache.end() ; ) {
|
||||
if (StringUtil::begins_with(it->first, responsePath)) {
|
||||
if (StringUtil::isDescendantOf(it->first, responsePath)) {
|
||||
removedPaths.emplace_back(move(it->first));
|
||||
it = _cache.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Assume that we won't need this at this point, UNREGISTER_PATH is rare
|
||||
_oldCache.clear();
|
||||
}
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
for (auto& path : removedPaths)
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
||||
|
||||
@@ -116,57 +125,57 @@ void RemotePathChecker::workerThreadLoop()
|
||||
auto state = _StrToFileState(responseStatus);
|
||||
bool wasAsked = asked.erase(responsePath) > 0;
|
||||
|
||||
bool changed = false;
|
||||
bool updateView = false;
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
bool wasCached = _cache.find(responsePath) != _cache.end();
|
||||
if (wasAsked || wasCached) {
|
||||
auto &it = _cache[responsePath];
|
||||
changed = (it != state);
|
||||
it = state;
|
||||
auto it = _cache.find(responsePath);
|
||||
if (it == _cache.end()) {
|
||||
// The client only approximates requested files, if the bloom
|
||||
// filter becomes saturated after navigating multiple directories we'll start getting
|
||||
// status pushes that we never requested and fill our cache. Ignore those.
|
||||
if (!wasAsked) {
|
||||
continue;
|
||||
}
|
||||
it = _cache.insert(make_pair(responsePath, StateNone)).first;
|
||||
}
|
||||
|
||||
updateView = it->second != state;
|
||||
it->second = state;
|
||||
}
|
||||
if (changed) {
|
||||
if (updateView) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
}
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
// Keep the old states to continue having something to display while the new state is
|
||||
// requested from the client, triggered by clearing _cache.
|
||||
_oldCache.insert(_cache.cbegin(), _cache.cend());
|
||||
|
||||
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
||||
std::unordered_map<std::wstring, FileState> cache;
|
||||
swap(cache, _cache);
|
||||
lock.unlock();
|
||||
// Let explorer know about the invalidated cache entries, it will re-request the ones it needs.
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cache.clear();
|
||||
_oldCache.clear();
|
||||
_watchedDirectories.clear();
|
||||
_connected = connected = false;
|
||||
}
|
||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||
atomic_store(&_watchedDirectories, make_shared<const vector<wstring>>());
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_connected = connected = false;
|
||||
|
||||
if (_stop) return;
|
||||
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
||||
std::unordered_map<std::wstring, FileState> cache;
|
||||
swap(cache, _cache);
|
||||
lock.unlock();
|
||||
// Let explorer know about each invalidated cache entry that needs to get its icon removed.
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE handles[2] = { _newQueries, socket.Event() };
|
||||
WaitForMultipleObjects(2, handles, false, 0);
|
||||
if (_stop) return;
|
||||
|
||||
HANDLE handles[2] = { _newQueries, socket.Event() };
|
||||
WaitForMultipleObjects(2, handles, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RemotePathChecker::RemotePathChecker()
|
||||
: _connected(false)
|
||||
: _watchedDirectories(make_shared<const vector<wstring>>())
|
||||
, _connected(false)
|
||||
, _newQueries(CreateEvent(NULL, true, true, NULL))
|
||||
, _thread([this]{ this->workerThreadLoop(); })
|
||||
, _thread([this]{ this->workerThreadLoop(); })
|
||||
{
|
||||
}
|
||||
|
||||
@@ -179,10 +188,9 @@ RemotePathChecker::~RemotePathChecker()
|
||||
CloseHandle(_newQueries);
|
||||
}
|
||||
|
||||
vector<wstring> RemotePathChecker::WatchedDirectories()
|
||||
std::shared_ptr<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
return _watchedDirectories;
|
||||
return atomic_load(&_watchedDirectories);
|
||||
}
|
||||
|
||||
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||
@@ -198,44 +206,39 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||
|
||||
auto it = _cache.find(path);
|
||||
if (it != _cache.end()) {
|
||||
// The path is in our cache, and we'll get updates pushed if the status changes.
|
||||
*state = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Re-request the status while we display what we have in _oldCache
|
||||
_pending.push(filePath);
|
||||
|
||||
it = _oldCache.find(path);
|
||||
bool foundInOldCache = it != _oldCache.end();
|
||||
if (foundInOldCache)
|
||||
*state = it->second;
|
||||
|
||||
lock.unlock();
|
||||
SetEvent(_newQueries);
|
||||
return foundInOldCache;
|
||||
return false;
|
||||
}
|
||||
|
||||
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
|
||||
{
|
||||
if (str == L"NOP" || str == L"NONE") {
|
||||
return StateNone;
|
||||
} else if (str == L"SYNC" || str == L"NEW") {
|
||||
return StateSync;
|
||||
} else if (str == L"SYNC+SWM" || str == L"NEW+SWM") {
|
||||
return StateSync;
|
||||
} else if (str == L"OK") {
|
||||
return StateOk;
|
||||
} else if (str == L"OK+SWM") {
|
||||
return StateOkSWM;
|
||||
} else if (str == L"IGNORE") {
|
||||
return StateWarning;
|
||||
} else if (str == L"IGNORE+SWM") {
|
||||
return StateWarning;
|
||||
} else if (str == L"ERROR") {
|
||||
return StateError;
|
||||
} else if (str == L"ERROR+SWM") {
|
||||
return StateError;
|
||||
}
|
||||
if (str == L"NOP" || str == L"NONE") {
|
||||
return StateNone;
|
||||
} else if (str == L"SYNC" || str == L"NEW") {
|
||||
return StateSync;
|
||||
} else if (str == L"SYNC+SWM" || str == L"NEW+SWM") {
|
||||
return StateSync;
|
||||
} else if (str == L"OK") {
|
||||
return StateOk;
|
||||
} else if (str == L"OK+SWM") {
|
||||
return StateOkSWM;
|
||||
} else if (str == L"IGNORE") {
|
||||
return StateWarning;
|
||||
} else if (str == L"IGNORE+SWM") {
|
||||
return StateWarning;
|
||||
} else if (str == L"ERROR") {
|
||||
return StateError;
|
||||
} else if (str == L"ERROR+SWM") {
|
||||
return StateError;
|
||||
}
|
||||
|
||||
return StateNone;
|
||||
return StateNone;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
@@ -27,21 +28,21 @@
|
||||
|
||||
class __declspec(dllexport) RemotePathChecker {
|
||||
public:
|
||||
enum FileState {
|
||||
// Order synced with OCOverlay
|
||||
StateError = 0,
|
||||
StateOk, StateOkSWM,
|
||||
StateSync,
|
||||
StateWarning,
|
||||
StateNone
|
||||
};
|
||||
RemotePathChecker();
|
||||
enum FileState {
|
||||
// Order synced with OCOverlay
|
||||
StateError = 0,
|
||||
StateOk, StateOkSWM,
|
||||
StateSync,
|
||||
StateWarning,
|
||||
StateNone
|
||||
};
|
||||
RemotePathChecker();
|
||||
~RemotePathChecker();
|
||||
std::vector<std::wstring> WatchedDirectories();
|
||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||
std::shared_ptr<const std::vector<std::wstring>> WatchedDirectories() const;
|
||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||
|
||||
private:
|
||||
FileState _StrToFileState(const std::wstring &str);
|
||||
FileState _StrToFileState(const std::wstring &str);
|
||||
std::mutex _mutex;
|
||||
std::atomic<bool> _stop;
|
||||
|
||||
@@ -52,8 +53,9 @@ private:
|
||||
std::queue<std::wstring> _pending;
|
||||
|
||||
std::unordered_map<std::wstring, FileState> _cache;
|
||||
std::unordered_map<std::wstring, FileState> _oldCache;
|
||||
std::vector<std::wstring> _watchedDirectories;
|
||||
// The vector is const since it will be accessed from multiple threads through OCOverlay::IsMemberOf.
|
||||
// Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr.
|
||||
std::shared_ptr<const std::vector<std::wstring>> _watchedDirectories;
|
||||
bool _connected;
|
||||
|
||||
|
||||
@@ -61,7 +63,7 @@ private:
|
||||
//std::condition_variable _newQueries;
|
||||
HANDLE _newQueries;
|
||||
|
||||
std::thread _thread;
|
||||
std::thread _thread;
|
||||
void workerThreadLoop();
|
||||
};
|
||||
|
||||
|
||||
@@ -21,18 +21,18 @@
|
||||
|
||||
std::string StringUtil::toUtf8(const wchar_t *utf16, int len)
|
||||
{
|
||||
if (len < 0) {
|
||||
len = (int) wcslen(utf16);
|
||||
}
|
||||
if (len < 0) {
|
||||
len = (int) wcslen(utf16);
|
||||
}
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||
return converter.to_bytes(utf16, utf16+len);
|
||||
}
|
||||
|
||||
std::wstring StringUtil::toUtf16(const char *utf8, int len)
|
||||
{
|
||||
if (len < 0) {
|
||||
len = (int) strlen(utf8);
|
||||
}
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||
if (len < 0) {
|
||||
len = (int) strlen(utf8);
|
||||
}
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||
return converter.from_bytes(utf8, utf8+len);
|
||||
}
|
||||
|
||||
@@ -20,15 +20,30 @@
|
||||
|
||||
class __declspec(dllexport) StringUtil {
|
||||
public:
|
||||
static std::string toUtf8(const wchar_t* utf16, int len = -1);
|
||||
static std::wstring toUtf16(const char* utf8, int len = -1);
|
||||
static std::string toUtf8(const wchar_t* utf16, int len = -1);
|
||||
static std::wstring toUtf16(const char* utf8, int len = -1);
|
||||
|
||||
template<class T>
|
||||
static bool begins_with(const T& input, const T& match)
|
||||
{
|
||||
return input.size() >= match.size()
|
||||
&& std::equal(match.begin(), match.end(), input.begin());
|
||||
}
|
||||
template<class T>
|
||||
static bool begins_with(const T& input, const T& match)
|
||||
{
|
||||
return input.size() >= match.size()
|
||||
&& std::equal(match.begin(), match.end(), input.begin());
|
||||
}
|
||||
|
||||
static bool isDescendantOf(const std::wstring& child, const std::wstring& parent) {
|
||||
return isDescendantOf(child.c_str(), child.size(), parent.c_str(), parent.size());
|
||||
}
|
||||
|
||||
static bool isDescendantOf(PCWSTR child, size_t childLength, const std::wstring& parent) {
|
||||
return isDescendantOf(child, childLength, parent.c_str(), parent.size());
|
||||
}
|
||||
|
||||
static bool isDescendantOf(PCWSTR child, size_t childLength, PCWSTR parent, size_t parentLength) {
|
||||
if (!parentLength)
|
||||
return false;
|
||||
return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\'))
|
||||
&& wcsncmp(child, parent, parentLength) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // STRINGUTIL_H
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// This is the number that will end up in the version window of the DLLs.
|
||||
// Increment this version before committing a new build if you are today's shell_integration build master.
|
||||
#define OCEXT_BUILD_NUM 43
|
||||
#define OCEXT_BUILD_NUM 44
|
||||
|
||||
#define STRINGIZE2(s) #s
|
||||
#define STRINGIZE(s) STRINGIZE2(s)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# TODO: OSX and LIB_ONLY seem to require this to go to binary dir only
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
endif()
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
|
||||
|
||||
|
||||
@@ -46,11 +46,17 @@ AccountManager *AccountManager::instance()
|
||||
bool AccountManager::restore()
|
||||
{
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
if (settings->status() != QSettings::NoError) {
|
||||
qDebug() << "Could not read settings from" << settings->fileName()
|
||||
<< settings->status();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are no accounts, check the old format.
|
||||
if (settings->childGroups().isEmpty()
|
||||
&& !settings->contains(QLatin1String(versionC))) {
|
||||
return restoreFromLegacySettings();
|
||||
restoreFromLegacySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (const auto& accountId, settings->childGroups()) {
|
||||
@@ -69,6 +75,9 @@ bool AccountManager::restore()
|
||||
|
||||
bool AccountManager::restoreFromLegacySettings()
|
||||
{
|
||||
qDebug() << "Migrate: restoreFromLegacySettings, checking settings group"
|
||||
<< Theme::instance()->appName();
|
||||
|
||||
// try to open the correctly themed settings
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
|
||||
@@ -86,7 +95,7 @@ bool AccountManager::restoreFromLegacySettings()
|
||||
|
||||
QFileInfo fi( oCCfgFile );
|
||||
if( fi.isReadable() ) {
|
||||
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
|
||||
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
|
||||
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
||||
|
||||
// Check the theme url to see if it is the same url that the oC config was for
|
||||
@@ -101,9 +110,7 @@ bool AccountManager::restoreFromLegacySettings()
|
||||
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||
if( oCUrl == overrideUrl ) {
|
||||
settings.reset( oCSettings );
|
||||
} else {
|
||||
delete oCSettings;
|
||||
settings = std::move(oCSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,8 +203,8 @@ void AccountManager::saveAccountHelper(Account* acc, QSettings& settings, bool s
|
||||
if (acc->_am) {
|
||||
CookieJar* jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
||||
if (jar) {
|
||||
qDebug() << "Saving cookies.";
|
||||
jar->save();
|
||||
qDebug() << "Saving cookies." << acc->cookieJarPath();
|
||||
jar->save(acc->cookieJarPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,6 +242,9 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
|
||||
} else {
|
||||
acc->setUrl(urlConfig.toUrl());
|
||||
}
|
||||
|
||||
qDebug() << "Account for" << acc->url() << "using auth type" << authType;
|
||||
|
||||
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
|
||||
|
||||
// We want to only restore settings for that auth type and the user value
|
||||
@@ -286,6 +296,8 @@ void AccountManager::deleteAccount(AccountState* account)
|
||||
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
||||
_accounts.erase(it);
|
||||
|
||||
QFile::remove(account->account()->cookieJarPath());
|
||||
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
settings->remove(account->account()->id());
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ public:
|
||||
|
||||
/**
|
||||
* Creates account objects from a given settings file.
|
||||
* return true if the account was restored
|
||||
*
|
||||
* Returns false if there was an error reading the settings,
|
||||
* but note that settings not existing is not an error.
|
||||
*/
|
||||
bool restore();
|
||||
|
||||
|
||||
@@ -675,8 +675,13 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
||||
ui->selectiveSyncButtons->setVisible(true);
|
||||
ui->bigFolderUi->setVisible(false);
|
||||
} else {
|
||||
QString wholeMsg = tr("There are new folders that were not synchronized because they are too big: ") + msg;
|
||||
ui->selectiveSyncNotification->setText(wholeMsg);
|
||||
ConfigFile cfg;
|
||||
QString info =
|
||||
!cfg.confirmExternalStorage() ? tr("There are folders that were not synchronized because they are too big: ") :
|
||||
!cfg.newBigFolderSizeLimit().first ? tr("There are folders that were not synchronized because they are external storages: ") :
|
||||
tr("There are folders that were not synchronized because they are too big or external storages: ");
|
||||
|
||||
ui->selectiveSyncNotification->setText(info + msg);
|
||||
ui->selectiveSyncButtons->setVisible(false);
|
||||
ui->bigFolderUi->setVisible(true);
|
||||
shouldBeVisible = true;
|
||||
|
||||
@@ -156,7 +156,23 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
||||
|
||||
AccountManager::instance()->restore();
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
// If there is an error reading the account settings, try again
|
||||
// after a couple of seconds, if that fails, give up.
|
||||
// (non-existence is not an error)
|
||||
Utility::sleep(5);
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
qDebug() << "Could not read the account settings, quitting";
|
||||
QMessageBox::critical(
|
||||
0,
|
||||
tr("Error accessing the configuration file"),
|
||||
tr("There was an error while accessing the configuration "
|
||||
"file at %1.").arg(ConfigFile().configFile()),
|
||||
tr("Quit ownCloud"));
|
||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FolderMan::instance()->setSyncEnabled(true);
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ void ShibbolethCredentials::fetchFromKeychain()
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
@@ -309,7 +309,7 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie)
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
// we don't really care if it works...
|
||||
//connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->setTextData(QString::fromUtf8(cookie.toRawForm()));
|
||||
job->start();
|
||||
}
|
||||
@@ -318,7 +318,7 @@ void ShibbolethCredentials::removeShibCookie()
|
||||
{
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
+70
-169
@@ -46,17 +46,13 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
const char oldJournalPath[] = ".csync_journal.db";
|
||||
|
||||
Folder::Folder(const FolderDefinition& definition,
|
||||
AccountState* accountState,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, _accountState(accountState)
|
||||
, _definition(definition)
|
||||
, _csyncError(false)
|
||||
, _csyncUnavail(false)
|
||||
, _wipeDb(false)
|
||||
, _proxyDirty(true)
|
||||
, _lastSyncDuration(0)
|
||||
, _consecutiveFailingSyncs(0)
|
||||
@@ -89,8 +85,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
|
||||
connect(_accountState.data(), SIGNAL(isConnectedChanged()), this, SIGNAL(canSyncChanged()));
|
||||
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
||||
connect(_engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||
|
||||
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
||||
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
||||
@@ -104,9 +98,10 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
SLOT(slotAboutToRestoreBackup(bool*)));
|
||||
connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
|
||||
connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo)));
|
||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString)), this, SLOT(slotNewBigFolderDiscovered(QString)));
|
||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString,bool)),
|
||||
this, SLOT(slotNewBigFolderDiscovered(QString,bool)));
|
||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
SLOT(slotLogPropagationStart()));
|
||||
@@ -140,13 +135,13 @@ void Folder::checkLocalPath()
|
||||
} else {
|
||||
// Check directory again
|
||||
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
||||
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isDir() ) {
|
||||
_syncResult.setErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isReadable() ) {
|
||||
_syncResult.setErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
}
|
||||
}
|
||||
@@ -269,8 +264,8 @@ SyncResult Folder::syncResult() const
|
||||
|
||||
void Folder::prepareToSync()
|
||||
{
|
||||
_syncResult.reset();
|
||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||
_syncResult.clearErrors();
|
||||
}
|
||||
|
||||
void Folder::slotRunEtagJob()
|
||||
@@ -324,120 +319,33 @@ void Folder::etagRetreivedFromSyncEngine(const QString& etag)
|
||||
}
|
||||
|
||||
|
||||
void Folder::bubbleUpSyncResult()
|
||||
void Folder::showSyncResultPopup()
|
||||
{
|
||||
// count new, removed and updated items
|
||||
int newItems = 0;
|
||||
int removedItems = 0;
|
||||
int updatedItems = 0;
|
||||
int ignoredItems = 0;
|
||||
int renamedItems = 0;
|
||||
int conflictItems = 0;
|
||||
int errorItems = 0;
|
||||
|
||||
SyncFileItemPtr firstItemNew;
|
||||
SyncFileItemPtr firstItemDeleted;
|
||||
SyncFileItemPtr firstItemUpdated;
|
||||
SyncFileItemPtr firstItemRenamed;
|
||||
SyncFileItemPtr firstConflictItem;
|
||||
SyncFileItemPtr firstItemError;
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
foreach (const SyncFileItemPtr &item, _syncResult.syncFileItemVector() ) {
|
||||
// Process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
slotSyncError( tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
errorItems++;
|
||||
if (!firstItemError) {
|
||||
firstItemError = item;
|
||||
}
|
||||
} else if( item->_status == SyncFileItem::FileIgnored ) {
|
||||
// ignored files don't show up in notifications
|
||||
continue;
|
||||
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||
conflictItems++;
|
||||
if (!firstConflictItem) {
|
||||
firstConflictItem = item;
|
||||
}
|
||||
} else {
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
if (!item->hasErrorStatus() && item->_direction == SyncFileItem::Down) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
newItems++;
|
||||
if (!firstItemNew)
|
||||
firstItemNew = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
removedItems++;
|
||||
if (!firstItemDeleted)
|
||||
firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
updatedItems++;
|
||||
if (!firstItemUpdated)
|
||||
firstItemUpdated = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (!firstItemRenamed) {
|
||||
firstItemRenamed = item;
|
||||
}
|
||||
renamedItems++;
|
||||
break;
|
||||
default:
|
||||
// nothing.
|
||||
break;
|
||||
}
|
||||
} else if( item->_direction == SyncFileItem::None ) { // ignored files counting.
|
||||
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||
ignoredItems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( _syncResult.firstItemNew() ) {
|
||||
createGuiLog( _syncResult.firstItemNew()->_file, LogStatusNew, _syncResult.numNewItems() );
|
||||
}
|
||||
if( _syncResult.firstItemDeleted() ) {
|
||||
createGuiLog( _syncResult.firstItemDeleted()->_file, LogStatusRemove, _syncResult.numRemovedItems() );
|
||||
}
|
||||
if( _syncResult.firstItemUpdated() ) {
|
||||
createGuiLog( _syncResult.firstItemUpdated()->_file, LogStatusUpdated, _syncResult.numUpdatedItems() );
|
||||
}
|
||||
|
||||
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
|
||||
_syncResult.setWarnCount(ignoredItems);
|
||||
|
||||
if( firstItemNew ) {
|
||||
createGuiLog( firstItemNew->_file, LogStatusNew, newItems );
|
||||
}
|
||||
if( firstItemDeleted ) {
|
||||
createGuiLog( firstItemDeleted->_file, LogStatusRemove, removedItems );
|
||||
}
|
||||
if( firstItemUpdated ) {
|
||||
createGuiLog( firstItemUpdated->_file, LogStatusUpdated, updatedItems );
|
||||
}
|
||||
|
||||
if( firstItemRenamed ) {
|
||||
if( _syncResult.firstItemRenamed() ) {
|
||||
LogStatus status(LogStatusRename);
|
||||
// if the path changes it's rather a move
|
||||
QDir renTarget = QFileInfo(firstItemRenamed->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(firstItemRenamed->_file).dir();
|
||||
QDir renTarget = QFileInfo(_syncResult.firstItemRenamed()->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(_syncResult.firstItemRenamed()->_file).dir();
|
||||
if(renTarget != renSource) {
|
||||
status = LogStatusMove;
|
||||
}
|
||||
createGuiLog( firstItemRenamed->_originalFile, status, renamedItems, firstItemRenamed->_renameTarget );
|
||||
createGuiLog( _syncResult.firstItemRenamed()->_originalFile, status, _syncResult.numRenamedItems(), _syncResult.firstItemRenamed()->_renameTarget );
|
||||
}
|
||||
|
||||
if( firstConflictItem ) {
|
||||
createGuiLog( firstConflictItem->_file, LogStatusConflict, conflictItems );
|
||||
if( _syncResult.firstConflictItem() ) {
|
||||
createGuiLog( _syncResult.firstConflictItem()->_file, LogStatusConflict, _syncResult.numConflictItems() );
|
||||
}
|
||||
createGuiLog( firstItemError->_file, LogStatusError, errorItems );
|
||||
createGuiLog( _syncResult.firstItemError()->_file, LogStatusError, _syncResult.numErrorItems() );
|
||||
|
||||
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
||||
}
|
||||
@@ -576,12 +484,6 @@ void Folder::slotWatchedPathChanged(const QString& path)
|
||||
scheduleThisFolderSoon();
|
||||
}
|
||||
|
||||
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
|
||||
void Folder::saveToSettings() const
|
||||
{
|
||||
// Remove first to make sure we don't get duplicates
|
||||
@@ -644,9 +546,6 @@ void Folder::slotTerminateSync()
|
||||
if( _engine->isSyncRunning() ) {
|
||||
_engine->abort();
|
||||
|
||||
// Do not display an error message, user knows his own actions.
|
||||
// _errors.append( tr("The CSync thread terminated.") );
|
||||
// _csyncError = true;
|
||||
setSyncState(SyncResult::SyncAbortRequested);
|
||||
}
|
||||
}
|
||||
@@ -694,10 +593,9 @@ bool Folder::setIgnoredFiles()
|
||||
// a QSet of files to load.
|
||||
ConfigFile cfg;
|
||||
QString systemList = cfg.excludeFile(ConfigFile::SystemScope);
|
||||
if( QFile::exists(systemList) ) {
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
}
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
|
||||
QString userList = cfg.excludeFile(ConfigFile::UserScope);
|
||||
if( QFile::exists(userList) ) {
|
||||
qDebug() << "==== adding user defined ignore list to csync:" << userList;
|
||||
@@ -728,19 +626,17 @@ void Folder::startSync(const QStringList &pathList)
|
||||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||
return;
|
||||
}
|
||||
_errors.clear();
|
||||
_csyncError = false;
|
||||
_csyncUnavail = false;
|
||||
|
||||
_timeSinceLastSyncStart.restart();
|
||||
_syncResult.clearErrors();
|
||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||
emit syncStateChange();
|
||||
|
||||
qDebug() << "*** Start syncing " << remoteUrl().toString() << " - client version"
|
||||
<< qPrintable(Theme::instance()->version());
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
if (!setIgnoredFiles())
|
||||
{
|
||||
slotSyncError(tr("Could not read system exclude file"));
|
||||
@@ -750,15 +646,15 @@ void Folder::startSync(const QStringList &pathList)
|
||||
|
||||
setDirtyNetworkLimits();
|
||||
|
||||
SyncOptions opt;
|
||||
ConfigFile cfgFile;
|
||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
quint64 limit = newFolderLimit.first ? newFolderLimit.second * 1000 * 1000 : -1; // convert from MB to B
|
||||
_engine->setNewBigFolderSizeLimit(limit);
|
||||
opt._newBigFolderSizeLimit = newFolderLimit.first ? newFolderLimit.second * 1000LL * 1000LL : -1; // convert from MB to B
|
||||
opt._confirmExternalStorage = cfgFile.confirmExternalStorage();
|
||||
_engine->setSyncOptions(opt);
|
||||
|
||||
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||
|
||||
emit syncStarted();
|
||||
@@ -789,8 +685,7 @@ void Folder::setDirtyNetworkLimits()
|
||||
|
||||
void Folder::slotSyncError(const QString& err)
|
||||
{
|
||||
_errors.append( err );
|
||||
_csyncError = true;
|
||||
_syncResult.appendErrorString(err);
|
||||
}
|
||||
|
||||
void Folder::slotSyncStarted()
|
||||
@@ -812,29 +707,26 @@ void Folder::slotSyncFinished(bool success)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
<< " SSL " << QSslSocket::sslLibraryVersionString().toUtf8().data()
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
|
||||
if( _csyncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR, warn count is" << _syncResult.warnCount();
|
||||
bool syncError = !_syncResult.errorStrings().isEmpty();
|
||||
if( syncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR";
|
||||
} else {
|
||||
qDebug() << "-> SyncEngine finished without problem.";
|
||||
}
|
||||
_fileLog->finish();
|
||||
bubbleUpSyncResult();
|
||||
showSyncResultPopup();
|
||||
|
||||
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
|
||||
if (_csyncError) {
|
||||
if (syncError) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** error Strings: " << _errors;
|
||||
_syncResult.setErrorStrings( _errors );
|
||||
qDebug() << " * owncloud csync thread finished with error";
|
||||
} else if (_csyncUnavail) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** csync not available.";
|
||||
} else if( _syncResult.warnCount() > 0 ) {
|
||||
// there have been warnings on the way.
|
||||
} else if( _syncResult.foundFilesNotSynced() ) {
|
||||
_syncResult.setStatus(SyncResult::Problem);
|
||||
} else if( _definition.paused ) {
|
||||
// Maybe the sync was terminated because the user paused the folder
|
||||
@@ -911,26 +803,28 @@ void Folder::slotFolderDiscovered(bool, QString folderName)
|
||||
// and hand the result over to the progress dispatcher.
|
||||
void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
||||
{
|
||||
if( !pi.isUpdatingEstimates() ) {
|
||||
// this is the beginning of a sync, set the warning level to 0
|
||||
_syncResult.setWarnCount(0);
|
||||
}
|
||||
emit progressInfo(pi);
|
||||
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
||||
}
|
||||
|
||||
// a item is completed: count the errors and forward to the ProgressDispatcher
|
||||
void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job)
|
||||
void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
if (Progress::isWarningKind(item._status)) {
|
||||
// Count all error conditions.
|
||||
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
_fileLog->logItem(item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item, job);
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
_syncResult.processCompletedItem(item);
|
||||
|
||||
_fileLog->logItem(*item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
|
||||
}
|
||||
|
||||
void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
||||
void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
|
||||
{
|
||||
auto newFolder = newF;
|
||||
if (!newFolder.endsWith(QLatin1Char('/'))) {
|
||||
@@ -955,9 +849,11 @@ void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
||||
journal->setSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, undecidedList);
|
||||
emit newBigFolderDiscovered(newFolder);
|
||||
}
|
||||
QString message = tr("A new folder larger than %1 MB has been added: %2.\n"
|
||||
"Please go in the settings to select it if you wish to download it.")
|
||||
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF);
|
||||
QString message = !isExternal ?
|
||||
(tr("A new folder larger than %1 MB has been added: %2.\n")
|
||||
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF))
|
||||
: (tr("A folder from an external storage has been added.\n"));
|
||||
message += tr("Please go in the settings to select it if you wish to download it.");
|
||||
|
||||
auto logger = Logger::instance();
|
||||
logger->postOptionalGuiLog(Theme::instance()->appNameGUI(), message);
|
||||
@@ -986,17 +882,22 @@ void Folder::setSaveBackwardsCompatible(bool save)
|
||||
_saveBackwardsCompatible = save;
|
||||
}
|
||||
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel)
|
||||
{
|
||||
ConfigFile cfgFile;
|
||||
if (!cfgFile.promptDeleteFiles())
|
||||
return;
|
||||
|
||||
QString msg =
|
||||
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 files were manually removed.\n"
|
||||
"Are you sure you want to perform this operation?");
|
||||
QString msg = dir == SyncFileItem::Down ?
|
||||
tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
||||
"These deletes will be synchronized to your local sync folder, making such files "
|
||||
"unavailable unless you have a right to restore. \n"
|
||||
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
|
||||
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.") :
|
||||
tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
|
||||
"synchronized with your server, making such files unavailable unless restored.\n"
|
||||
"Are you sure you want to sync those actions with the server?\n"
|
||||
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||
msg.arg(shortGuiLocalPath()));
|
||||
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||
|
||||
+3
-8
@@ -280,17 +280,15 @@ private slots:
|
||||
|
||||
void slotFolderDiscovered(bool local, QString folderName);
|
||||
void slotTransmissionProgress(const ProgressInfo& pi);
|
||||
void slotItemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||
void slotItemCompleted(const SyncFileItemPtr&);
|
||||
|
||||
void slotRunEtagJob();
|
||||
void etagRetreived(const QString &);
|
||||
void etagRetreivedFromSyncEngine(const QString &);
|
||||
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
|
||||
|
||||
void slotEmitFinishedDelayed();
|
||||
|
||||
void slotNewBigFolderDiscovered(const QString &);
|
||||
void slotNewBigFolderDiscovered(const QString &, bool isExternal);
|
||||
|
||||
void slotLogPropagationStart();
|
||||
|
||||
@@ -302,7 +300,7 @@ private slots:
|
||||
private:
|
||||
bool setIgnoredFiles();
|
||||
|
||||
void bubbleUpSyncResult();
|
||||
void showSyncResultPopup();
|
||||
|
||||
void checkLocalPath();
|
||||
|
||||
@@ -325,10 +323,7 @@ private:
|
||||
|
||||
SyncResult _syncResult;
|
||||
QScopedPointer<SyncEngine> _engine;
|
||||
QStringList _errors;
|
||||
bool _csyncError;
|
||||
bool _csyncUnavail;
|
||||
bool _wipeDb;
|
||||
bool _proxyDirty;
|
||||
QPointer<RequestEtagJob> _requestEtagJob;
|
||||
QString _lastEtag;
|
||||
|
||||
+10
-9
@@ -23,6 +23,7 @@
|
||||
#include "accountmanager.h"
|
||||
#include "filesystem.h"
|
||||
#include "lockwatcher.h"
|
||||
#include "asserts.h"
|
||||
#include <syncengine.h>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
@@ -48,7 +49,7 @@ FolderMan::FolderMan(QObject *parent) :
|
||||
_lockWatcher(new LockWatcher),
|
||||
_appRestartRequired(false)
|
||||
{
|
||||
Q_ASSERT(!_instance);
|
||||
ASSERT(!_instance);
|
||||
_instance = this;
|
||||
|
||||
_socketApi.reset(new SocketApi);
|
||||
@@ -115,7 +116,7 @@ void FolderMan::unloadFolder( Folder *f )
|
||||
disconnect(f, SIGNAL(syncPausedChanged(Folder*,bool)),
|
||||
this, SLOT(slotFolderSyncPaused(Folder*,bool)));
|
||||
disconnect(&f->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
||||
_socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
|
||||
_socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
|
||||
disconnect(f, SIGNAL(watchedFileChangedExternally(QString)),
|
||||
&f->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
||||
}
|
||||
@@ -133,12 +134,13 @@ int FolderMan::unloadAndDeleteAllFolders()
|
||||
delete f;
|
||||
cnt++;
|
||||
}
|
||||
ASSERT(_folderMap.isEmpty());
|
||||
|
||||
_lastSyncFolder = 0;
|
||||
_currentSyncFolder = 0;
|
||||
_scheduledFolders.clear();
|
||||
emit scheduleQueueChanged();
|
||||
|
||||
Q_ASSERT(_folderMap.count() == 0);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@@ -260,7 +262,6 @@ int FolderMan::setupFoldersMigration()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
QDir storageDir(cfg.configPath());
|
||||
storageDir.mkpath(QLatin1String("folders"));
|
||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||
|
||||
qDebug() << "* Setup folders from " << _folderConfigPath << "(migration)";
|
||||
@@ -463,7 +464,7 @@ void FolderMan::slotFolderSyncPaused( Folder *f, bool paused )
|
||||
void FolderMan::slotFolderCanSyncChanged()
|
||||
{
|
||||
Folder *f = qobject_cast<Folder*>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
if (f->canSync()) {
|
||||
_socketApi->slotRegisterPath(f->alias());
|
||||
} else {
|
||||
@@ -938,7 +939,7 @@ Folder* FolderMan::addFolderInternal(FolderDefinition folderDefinition,
|
||||
connect(folder, SIGNAL(syncPausedChanged(Folder*,bool)), SLOT(slotFolderSyncPaused(Folder*,bool)));
|
||||
connect(folder, SIGNAL(canSyncChanged()), SLOT(slotFolderCanSyncChanged()));
|
||||
connect(&folder->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
||||
_socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
|
||||
_socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
|
||||
connect(folder, SIGNAL(watchedFileChangedExternally(QString)),
|
||||
&folder->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
||||
|
||||
@@ -1121,7 +1122,7 @@ void FolderMan::setDirtyNetworkLimits()
|
||||
|
||||
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
{
|
||||
SyncResult overallResult(SyncResult::Undefined);
|
||||
SyncResult overallResult;
|
||||
|
||||
int cnt = folders.count();
|
||||
|
||||
@@ -1235,10 +1236,10 @@ SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
QString FolderMan::statusToString( SyncResult syncStatus, bool paused ) const
|
||||
QString FolderMan::statusToString( SyncResult::Status syncStatus, bool paused ) const
|
||||
{
|
||||
QString folderMessage;
|
||||
switch( syncStatus.status() ) {
|
||||
switch( syncStatus ) {
|
||||
case SyncResult::Undefined:
|
||||
folderMessage = tr( "Undefined State." );
|
||||
break;
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
/** Creates a new and empty local directory. */
|
||||
bool startFromScratch( const QString& );
|
||||
|
||||
QString statusToString(SyncResult, bool paused ) const;
|
||||
QString statusToString(SyncResult::Status, bool paused ) const;
|
||||
|
||||
static SyncResult accountStatus( const QList<Folder*> &folders );
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "folderman.h"
|
||||
#include "accountstate.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
#include <theme.h>
|
||||
#include <account.h>
|
||||
#include "folderstatusdelegate.h"
|
||||
@@ -29,6 +30,14 @@ Q_DECLARE_METATYPE(QPersistentModelIndex)
|
||||
namespace OCC {
|
||||
|
||||
static const char propertyParentIndexC[] = "oc_parentIndex";
|
||||
static const char propertyPermissionMap[] = "oc_permissionMap";
|
||||
|
||||
static QString removeTrailingSlash(const QString &s) {
|
||||
if (s.endsWith('/')) {
|
||||
return s.left(s.size() - 1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
FolderStatusModel::FolderStatusModel(QObject *parent)
|
||||
:QAbstractItemModel(parent), _accountState(0), _dirty(false)
|
||||
@@ -162,7 +171,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
case Qt::CheckStateRole:
|
||||
return x._checked;
|
||||
case Qt::DecorationRole:
|
||||
return QFileIconProvider().icon(QFileIconProvider::Folder);
|
||||
return QFileIconProvider().icon(x._isExternal ? QFileIconProvider::Network : QFileIconProvider::Folder);
|
||||
case Qt::ForegroundRole:
|
||||
if (x._isUndecided) {
|
||||
return QColor(Qt::red);
|
||||
@@ -368,6 +377,9 @@ FolderStatusModel::SubFolderInfo* FolderStatusModel::infoForIndex(const QModelIn
|
||||
if (parentInfo->hasLabel()) {
|
||||
return 0;
|
||||
}
|
||||
if (index.row() >= parentInfo->_subs.size()) {
|
||||
return 0;
|
||||
}
|
||||
return &parentInfo->_subs[index.row()];
|
||||
} else {
|
||||
if (index.row() >= _folders.count()) {
|
||||
@@ -469,14 +481,14 @@ QModelIndex FolderStatusModel::parent(const QModelIndex& child) const
|
||||
}
|
||||
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
||||
int i = 1;
|
||||
Q_ASSERT(pathIdx.at(0) < _folders.count());
|
||||
ASSERT(pathIdx.at(0) < _folders.count());
|
||||
if (pathIdx.count() == 1) {
|
||||
return createIndex(pathIdx.at(0), 0/*, nullptr*/);
|
||||
}
|
||||
|
||||
const SubFolderInfo *info = &_folders[pathIdx.at(0)];
|
||||
while (i < pathIdx.count() - 1) {
|
||||
Q_ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
info = &info->_subs[pathIdx.at(i)];
|
||||
++i;
|
||||
}
|
||||
@@ -537,12 +549,15 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
||||
path += info->_path;
|
||||
}
|
||||
LsColJob *job = new LsColJob(_accountState->account(), path, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size" << "http://owncloud.org/ns:permissions");
|
||||
job->setTimeout(60 * 1000);
|
||||
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
||||
SLOT(slotUpdateDirectories(QStringList)));
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
connect(job, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotGatherPermissions(const QString&, const QMap<QString,QString>&)));
|
||||
|
||||
job->start();
|
||||
|
||||
QPersistentModelIndex persistentIndex(parent);
|
||||
@@ -553,10 +568,24 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
||||
QTimer::singleShot(1000, this, SLOT(slotShowFetchProgress()));
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotGatherPermissions(const QString &href, const QMap<QString,QString> &map)
|
||||
{
|
||||
auto it = map.find("permissions");
|
||||
if (it == map.end())
|
||||
return;
|
||||
|
||||
auto job = sender();
|
||||
auto permissionMap = job->property(propertyPermissionMap).toMap();
|
||||
job->setProperty(propertyPermissionMap, QVariant()); // avoid a detach of the map while it is modified
|
||||
ASSERT(!href.endsWith(QLatin1Char('/')), "LsColXMLParser::parse should remove the trailing slash before calling us.");
|
||||
permissionMap[href] = *it;
|
||||
job->setProperty(propertyPermissionMap, permissionMap);
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
auto parentInfo = infoForIndex(idx);
|
||||
if (!parentInfo) {
|
||||
@@ -598,6 +627,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
selectiveSyncUndecidedSet.insert(str);
|
||||
}
|
||||
}
|
||||
const auto permissionMap = job->property(propertyPermissionMap).toMap();
|
||||
|
||||
QStringList sortedSubfolders = list;
|
||||
// skip the parent item (first in the list)
|
||||
@@ -618,8 +648,8 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
newInfo._folder = parentInfo->_folder;
|
||||
newInfo._pathIdx = parentInfo->_pathIdx;
|
||||
newInfo._pathIdx << newSubs.size();
|
||||
auto size = job ? job->_sizes.value(path) : 0;
|
||||
newInfo._size = size;
|
||||
newInfo._size = job->_sizes.value(path);
|
||||
newInfo._isExternal = permissionMap.value(removeTrailingSlash(path)).toString().contains("M");
|
||||
newInfo._path = relativePath;
|
||||
newInfo._name = relativePath.split('/', QString::SkipEmptyParts).last();
|
||||
|
||||
@@ -686,7 +716,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
if (!idx.isValid()) {
|
||||
return;
|
||||
@@ -701,7 +731,7 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
parentInfo->_fetched = true;
|
||||
} else {
|
||||
Q_ASSERT(!parentInfo->hasLabel());
|
||||
ASSERT(!parentInfo->hasLabel());
|
||||
beginInsertRows(idx, 0, 0);
|
||||
parentInfo->_hasError = true;
|
||||
endInsertRows();
|
||||
@@ -981,7 +1011,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
auto& pi = _folders[folderIndex]._progress;
|
||||
|
||||
SyncResult::Status state = f->syncResult().status();
|
||||
if (f->syncPaused()) {
|
||||
if (!f->canSync()) {
|
||||
// Reset progress info.
|
||||
pi = SubFolderInfo::Progress();
|
||||
} else if (state == SyncResult::NotYetStarted) {
|
||||
@@ -1012,18 +1042,10 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
// update the icon etc. now
|
||||
slotUpdateFolderState(f);
|
||||
|
||||
if (state == SyncResult::Success) {
|
||||
foreach (const SyncFileItemPtr &i, f->syncResult().syncFileItemVector()) {
|
||||
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (state == SyncResult::Success && f->syncResult().folderStructureWasChanged()) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,7 +1136,7 @@ void FolderStatusModel::slotSyncNoPendingBigFolders()
|
||||
void FolderStatusModel::slotNewBigFolder()
|
||||
{
|
||||
auto f = qobject_cast<Folder *>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
|
||||
int folderIndex = -1;
|
||||
for (int i = 0; i < _folders.count(); ++i) {
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
struct SubFolderInfo {
|
||||
SubFolderInfo()
|
||||
: _folder(0), _size(0), _fetched(false), _fetching(false),
|
||||
: _folder(0), _size(0), _isExternal(false), _fetched(false), _fetching(false),
|
||||
_hasError(false), _fetchingLabel(false), _isUndecided(false), _checked(Qt::Checked) {}
|
||||
Folder *_folder;
|
||||
QString _name;
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
QVector<int> _pathIdx;
|
||||
QVector<SubFolderInfo> _subs;
|
||||
qint64 _size;
|
||||
bool _isExternal;
|
||||
|
||||
bool _fetched; // If we did the LSCOL for this folder already
|
||||
bool _fetching; // Whether a LSCOL job is currently running
|
||||
@@ -113,6 +114,7 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void slotUpdateDirectories(const QStringList &);
|
||||
void slotGatherPermissions(const QString &name, const QMap<QString,QString> &properties);
|
||||
void slotLscolFinishedWithError(QNetworkReply *r);
|
||||
void slotFolderSyncStateChange(Folder* f);
|
||||
void slotFolderScheduleQueueChanged();
|
||||
|
||||
@@ -482,9 +482,8 @@ void FolderWizardRemotePath::showWarn( const QString& msg ) const
|
||||
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
layout->addWidget(new QLabel(tr("Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.")));
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
}
|
||||
|
||||
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
|
||||
@@ -501,13 +500,17 @@ void FolderWizardSelectiveSync::initializePage()
|
||||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
QStringList initialBlacklist;
|
||||
if (Theme::instance()->wizardSelectiveSyncDefaultNothing()) {
|
||||
initialBlacklist = QStringList("/");
|
||||
}
|
||||
_selectiveSync->setFolderInfo(targetPath, alias, initialBlacklist);
|
||||
QWizardPage::initializePage();
|
||||
}
|
||||
|
||||
bool FolderWizardSelectiveSync::validatePage()
|
||||
{
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_treeView->createBlackList()));
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_selectiveSync->createBlackList()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -517,7 +520,7 @@ void FolderWizardSelectiveSync::cleanupPage()
|
||||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
_selectiveSync->setFolderInfo(targetPath, alias);
|
||||
QWizardPage::cleanupPage();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class SelectiveSyncTreeView;
|
||||
class SelectiveSyncWidget;
|
||||
|
||||
class ownCloudInfo;
|
||||
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
virtual void cleanupPage() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -32,12 +32,14 @@
|
||||
|
||||
#include <QNetworkProxy>
|
||||
#include <QDir>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
_ui(new Ui::GeneralSettings)
|
||||
_ui(new Ui::GeneralSettings),
|
||||
_currentlyLoading(false)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
@@ -66,6 +68,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||
connect(_ui->crashreporterCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newFolderLimitCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newFolderLimitSpinBox, SIGNAL(valueChanged(int)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newExternalStorage, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
|
||||
#ifndef WITH_CRASHREPORTER
|
||||
_ui->crashreporterCheckBox->setVisible(false);
|
||||
@@ -85,6 +88,9 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||
_ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists());
|
||||
|
||||
connect(_ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));
|
||||
|
||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
||||
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState*)), this, SLOT(loadMiscSettings()));
|
||||
}
|
||||
|
||||
GeneralSettings::~GeneralSettings()
|
||||
@@ -99,6 +105,12 @@ QSize GeneralSettings::sizeHint() const {
|
||||
|
||||
void GeneralSettings::loadMiscSettings()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 4, 0 )
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading);
|
||||
_currentlyLoading = true;
|
||||
#else
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading, true);
|
||||
#endif
|
||||
ConfigFile cfgFile;
|
||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
||||
@@ -106,11 +118,14 @@ void GeneralSettings::loadMiscSettings()
|
||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
_ui->newFolderLimitCheckBox->setChecked(newFolderLimit.first);
|
||||
_ui->newFolderLimitSpinBox->setValue(newFolderLimit.second);
|
||||
_ui->newExternalStorage->setChecked(cfgFile.confirmExternalStorage());
|
||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||
}
|
||||
|
||||
void GeneralSettings::slotUpdateInfo()
|
||||
{
|
||||
OCUpdater *updater = dynamic_cast<OCUpdater*>(Updater::instance());
|
||||
// Note: the sparkle-updater is not an OCUpdater
|
||||
OCUpdater *updater = qobject_cast<OCUpdater*>(Updater::instance());
|
||||
if (ConfigFile().skipUpdateCheck()) {
|
||||
updater = 0; // don't show update info if updates are disabled
|
||||
}
|
||||
@@ -129,6 +144,8 @@ void GeneralSettings::slotUpdateInfo()
|
||||
|
||||
void GeneralSettings::saveMiscSettings()
|
||||
{
|
||||
if (_currentlyLoading)
|
||||
return;
|
||||
ConfigFile cfgFile;
|
||||
bool isChecked = _ui->monoIconsCheckBox->isChecked();
|
||||
cfgFile.setMonoIcons(isChecked);
|
||||
@@ -137,6 +154,7 @@ void GeneralSettings::saveMiscSettings()
|
||||
|
||||
cfgFile.setNewBigFolderSizeLimit(_ui->newFolderLimitCheckBox->isChecked(),
|
||||
_ui->newFolderLimitSpinBox->value());
|
||||
cfgFile.setConfirmExternalStorage(_ui->newExternalStorage->isChecked());
|
||||
}
|
||||
|
||||
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
|
||||
|
||||
@@ -45,13 +45,14 @@ private slots:
|
||||
void slotToggleOptionalDesktopNotifications(bool);
|
||||
void slotUpdateInfo();
|
||||
void slotIgnoreFilesEditor();
|
||||
void loadMiscSettings();
|
||||
|
||||
private:
|
||||
void loadMiscSettings();
|
||||
|
||||
Ui::GeneralSettings *_ui;
|
||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||
QPointer<SyncLogDialog> _syncLogDialog;
|
||||
bool _currentlyLoading;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>706</width>
|
||||
<width>785</width>
|
||||
<height>523</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -52,33 +52,37 @@
|
||||
<property name="title">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Edit &Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Edit &Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>555</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>555</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="newFolderLimitCheckBox">
|
||||
<property name="text">
|
||||
<string>Ask &confirmation before downloading folders larger than</string>
|
||||
<string>Ask for confirmation before synchronizing folders larger than</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
@@ -98,7 +102,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>MB</string>
|
||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -117,7 +121,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="newExternalStorage">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchronizing external storages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="crashreporterCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
@@ -130,23 +141,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<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>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
+2
-1
@@ -107,7 +107,8 @@ int main(int argc, char **argv)
|
||||
// if handleStartup returns true, main()
|
||||
// needs to terminate here, e.g. because
|
||||
// the updater is triggered
|
||||
if (Updater::instance()->handleStartup()) {
|
||||
Updater *updater = Updater::instance();
|
||||
if ( updater && updater->handleStartup()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "notificationwidget.h"
|
||||
#include "QProgressIndicator.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
@@ -33,8 +34,8 @@ void NotificationWidget::setActivity(const Activity& activity)
|
||||
{
|
||||
_myActivity = activity;
|
||||
|
||||
Q_ASSERT( !activity._accName.isEmpty() );
|
||||
_accountName = activity._accName;
|
||||
ASSERT(!_accountName.isEmpty());
|
||||
|
||||
// _ui._headerLabel->setText( );
|
||||
_ui._subjectLabel->setVisible( !activity._subject.isEmpty() );
|
||||
|
||||
@@ -533,9 +533,11 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
||||
if (f) {
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
|
||||
_ocWizard->selectiveSyncBlacklist());
|
||||
// The user already accepted the selective sync dialog. everything is in the white list
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
||||
if (!_ocWizard->isConfirmBigFolderChecked()) {
|
||||
// The user already accepted the selective sync dialog. everything is in the white list
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
||||
QStringList() << QLatin1String("/"));
|
||||
}
|
||||
}
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "syncfileitem.h"
|
||||
#include "folder.h"
|
||||
#include "openfilemanager.h"
|
||||
#include "owncloudpropagator.h"
|
||||
#include "activityitemdelegate.h"
|
||||
|
||||
#include "ui_protocolwidget.h"
|
||||
@@ -45,8 +44,8 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
||||
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,ProgressInfo)),
|
||||
this, SLOT(slotProgressInfo(QString,ProgressInfo)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItem,PropagatorJob)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItem,PropagatorJob)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItemPtr)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItemPtr)));
|
||||
|
||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int)));
|
||||
|
||||
@@ -222,15 +221,11 @@ void ProtocolWidget::slotProgressInfo( const QString& folder, const ProgressInfo
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItem &item, const PropagatorJob &job)
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
||||
{
|
||||
if (qobject_cast<const PropagateDirectory*>(&job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, item);
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
|
||||
if(line) {
|
||||
if( item.hasErrorStatus() ) {
|
||||
if( item->hasErrorStatus() ) {
|
||||
_issueItemView->insertTopLevelItem(0, line);
|
||||
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
||||
} else {
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItem& item, const PropagatorJob& job);
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItemPtr& item);
|
||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "networkjobs.h"
|
||||
#include "theme.h"
|
||||
#include "folderman.h"
|
||||
#include "configfile.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTreeWidget>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <QScopedValueRollback>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -54,32 +56,48 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||
SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _account(account)
|
||||
, _inserting(false)
|
||||
, _folderTree(new QTreeWidget(this))
|
||||
{
|
||||
_loading = new QLabel(tr("Loading ..."), this);
|
||||
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
setColumnCount(2);
|
||||
_loading = new QLabel(tr("Loading ..."), _folderTree);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
auto header = new QLabel(this);
|
||||
header->setText(tr("Deselect remote folders you do not wish to synchronize."));
|
||||
header->setWordWrap(true);
|
||||
layout->addWidget(header);
|
||||
|
||||
layout->addWidget(_folderTree);
|
||||
|
||||
connect(_folderTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
||||
SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(_folderTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
|
||||
SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
_folderTree->setSortingEnabled(true);
|
||||
_folderTree->sortByColumn(0, Qt::AscendingOrder);
|
||||
_folderTree->setColumnCount(2);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
#else
|
||||
header()->resizeSection(0, sizeHint().width()/2);
|
||||
_folderTree->header()->resizeSection(0, sizeHint().width()/2);
|
||||
#endif
|
||||
header()->setStretchLastSection(true);
|
||||
headerItem()->setText(0, tr("Name"));
|
||||
headerItem()->setText(1, tr("Size"));
|
||||
_folderTree->header()->setStretchLastSection(true);
|
||||
_folderTree->headerItem()->setText(0, tr("Name"));
|
||||
_folderTree->headerItem()->setText(1, tr("Size"));
|
||||
}
|
||||
|
||||
QSize SelectiveSyncTreeView::sizeHint() const
|
||||
QSize SelectiveSyncWidget::sizeHint() const
|
||||
{
|
||||
return QTreeView::sizeHint().expandedTo(QSize(400, 400));
|
||||
return QWidget::sizeHint().expandedTo(QSize(600, 600));
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::refreshFolders()
|
||||
void SelectiveSyncWidget::refreshFolders()
|
||||
{
|
||||
LsColJob *job = new LsColJob(_account, _folderPath, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||
@@ -88,12 +106,12 @@ void SelectiveSyncTreeView::refreshFolders()
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
job->start();
|
||||
clear();
|
||||
_folderTree->clear();
|
||||
_loading->show();
|
||||
_loading->move(10,header()->height() + 10);
|
||||
_loading->move(10, _folderTree->header()->height() + 10);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
void SelectiveSyncWidget::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
{
|
||||
_folderPath = folderPath;
|
||||
if (_folderPath.startsWith(QLatin1Char('/'))) {
|
||||
@@ -116,7 +134,7 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
{
|
||||
QFileIconProvider prov;
|
||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||
@@ -159,13 +177,13 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
||||
}
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
QScopedValueRollback<bool> isInserting(_inserting);
|
||||
_inserting = true;
|
||||
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(_folderTree->topLevelItem(0));
|
||||
|
||||
QUrl url = _account->davUrl();
|
||||
QString pathToRemove = url.path();
|
||||
@@ -206,15 +224,11 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
root = new SelectiveSyncTreeViewItem(this);
|
||||
root = new SelectiveSyncTreeViewItem(_folderTree);
|
||||
root->setText(0, _rootName);
|
||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||
root->setData(0, Qt::UserRole, QString());
|
||||
if (_oldBlackList.isEmpty()) {
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
} else {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
}
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
||||
if (size >= 0) {
|
||||
root->setText(1, Utility::octetsToString(size));
|
||||
@@ -236,10 +250,19 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
recursiveInsert(root, paths, path, size);
|
||||
}
|
||||
|
||||
// Root is partially checked if any children are not checked
|
||||
for (int i = 0; i < root->childCount(); ++i) {
|
||||
const auto child = root->child(i);
|
||||
if (child->checkState(0) != Qt::Checked) {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
root->setExpanded(true);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
{
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
_loading->setText(tr("No subfolders currently on the server."));
|
||||
@@ -249,7 +272,7 @@ void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
_loading->resize(_loading->sizeHint()); // because it's not in a layout
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||
void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
|
||||
{
|
||||
QString dir = item->data(0, Qt::UserRole).toString();
|
||||
if (dir.isEmpty()) return;
|
||||
@@ -264,7 +287,7 @@ void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
{
|
||||
if (col != 0 || _inserting)
|
||||
return;
|
||||
@@ -322,10 +345,10 @@ void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
}
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||
QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return QStringList();
|
||||
|
||||
@@ -354,15 +377,15 @@ QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::oldBlackList() const
|
||||
QStringList SelectiveSyncWidget::oldBlackList() const
|
||||
{
|
||||
return _oldBlackList;
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncTreeView::estimatedSize(QTreeWidgetItem* root)
|
||||
qint64 SelectiveSyncWidget::estimatedSize(QTreeWidgetItem* root)
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return -1;
|
||||
|
||||
@@ -396,10 +419,10 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, Folder* folder, QWi
|
||||
_okButton(0) // defined in init()
|
||||
{
|
||||
bool ok;
|
||||
init(account, tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
|
||||
init(account);
|
||||
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
||||
if( ok ) {
|
||||
_treeView->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
_selectiveSync->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
} else {
|
||||
_okButton->setEnabled(false);
|
||||
}
|
||||
@@ -411,22 +434,16 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, const QString &fold
|
||||
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
|
||||
: QDialog(parent, f), _folder(0)
|
||||
{
|
||||
init(account,
|
||||
Theme::instance()->wizardSelectiveSyncDefaultNothing() ?
|
||||
tr("Choose What to Sync: Select remote subfolders you wish to synchronize.") :
|
||||
tr("Choose What to Sync: Deselect remote subfolders you do not wish to synchronize."));
|
||||
_treeView->setFolderInfo(folder, folder, blacklist);
|
||||
init(account);
|
||||
_selectiveSync->setFolderInfo(folder, folder, blacklist);
|
||||
}
|
||||
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account, const QString &labelText)
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account)
|
||||
{
|
||||
setWindowTitle(tr("Choose What to Sync"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
auto label = new QLabel(labelText);
|
||||
label->setWordWrap(true);
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
|
||||
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
|
||||
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
@@ -444,7 +461,7 @@ void SelectiveSyncDialog::accept()
|
||||
if( ! ok ) {
|
||||
return;
|
||||
}
|
||||
QStringList blackList = _treeView->createBlackList();
|
||||
QStringList blackList = _selectiveSync->createBlackList();
|
||||
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
||||
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
@@ -467,19 +484,18 @@ void SelectiveSyncDialog::accept()
|
||||
|
||||
QStringList SelectiveSyncDialog::createBlackList() const
|
||||
{
|
||||
return _treeView->createBlackList();
|
||||
return _selectiveSync->createBlackList();
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncDialog::oldBlackList() const
|
||||
{
|
||||
return _treeView->oldBlackList();
|
||||
return _selectiveSync->oldBlackList();
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncDialog::estimatedSize()
|
||||
{
|
||||
return _treeView->estimatedSize();
|
||||
return _selectiveSync->estimatedSize();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -26,40 +26,50 @@ namespace OCC {
|
||||
class Folder;
|
||||
|
||||
/**
|
||||
* @brief The SelectiveSyncTreeView class
|
||||
* @brief The SelectiveSyncWidget contains a folder tree with labels
|
||||
* @ingroup gui
|
||||
*/
|
||||
class SelectiveSyncTreeView : public QTreeWidget {
|
||||
class SelectiveSyncWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SelectiveSyncTreeView(AccountPtr account, QWidget* parent = 0);
|
||||
explicit SelectiveSyncWidget(AccountPtr account, QWidget* parent = 0);
|
||||
|
||||
/// Returns a list of blacklisted paths, each including the trailing /
|
||||
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
||||
|
||||
/** Returns the oldBlackList passed into setFolderInfo(), except that
|
||||
* a "/" entry is expanded to all top-level folder names.
|
||||
*/
|
||||
QStringList oldBlackList() const;
|
||||
|
||||
// Estimates the total size of checked items (recursively)
|
||||
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
||||
void refreshFolders();
|
||||
|
||||
// oldBlackList is a list of excluded paths, each including a trailing /
|
||||
void setFolderInfo(const QString &folderPath, const QString &rootName,
|
||||
const QStringList &oldBlackList = QStringList());
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void slotUpdateDirectories(QStringList);
|
||||
void slotItemExpanded(QTreeWidgetItem *);
|
||||
void slotItemChanged(QTreeWidgetItem*,int);
|
||||
void slotLscolFinishedWithError(QNetworkReply*);
|
||||
private:
|
||||
void refreshFolders();
|
||||
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
|
||||
|
||||
AccountPtr _account;
|
||||
|
||||
QString _folderPath;
|
||||
QString _rootName;
|
||||
QStringList _oldBlackList;
|
||||
|
||||
bool _inserting; // set to true when we are inserting new items on the list
|
||||
AccountPtr _account;
|
||||
QLabel *_loading;
|
||||
|
||||
QTreeWidget *_folderTree;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -85,9 +95,9 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void init(const AccountPtr &account, const QString &label);
|
||||
void init(const AccountPtr &account);
|
||||
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
Folder *_folder;
|
||||
QPushButton *_okButton;
|
||||
|
||||
+153
-102
@@ -31,9 +31,12 @@
|
||||
#include "accountstate.h"
|
||||
#include "account.h"
|
||||
#include "capabilities.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
#include <QMetaMethod>
|
||||
#include <QMetaObject>
|
||||
#include <QStringList>
|
||||
#include <QScopedPointer>
|
||||
@@ -56,6 +59,8 @@
|
||||
// The second number should be changed when there are new features.
|
||||
#define MIRALL_SOCKET_API_VERSION "1.0"
|
||||
|
||||
#define DEBUG qDebug() << "SocketApi: "
|
||||
|
||||
static inline QString removeTrailingSlash(QString path)
|
||||
{
|
||||
Q_ASSERT(path.endsWith(QLatin1Char('/')));
|
||||
@@ -63,9 +68,89 @@ static inline QString removeTrailingSlash(QString path)
|
||||
return path;
|
||||
}
|
||||
|
||||
static QString buildMessage(const QString& verb, const QString &path, const QString &status = QString::null )
|
||||
{
|
||||
QString msg(verb);
|
||||
|
||||
if( !status.isEmpty() ) {
|
||||
msg.append(QLatin1Char(':'));
|
||||
msg.append(status);
|
||||
}
|
||||
if( !path.isEmpty() ) {
|
||||
msg.append(QLatin1Char(':'));
|
||||
QFileInfo fi(path);
|
||||
msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
|
||||
#define DEBUG qDebug() << "SocketApi: "
|
||||
class BloomFilter {
|
||||
// Initialize with m=1024 bits and k=2 (high and low 16 bits of a qHash).
|
||||
// For a client navigating in less than 100 directories, this gives us a probability less than (1-e^(-2*100/1024))^2 = 0.03147872136 false positives.
|
||||
const static int NumBits = 1024;
|
||||
|
||||
public:
|
||||
BloomFilter() : hashBits(NumBits) { }
|
||||
|
||||
void storeHash(uint hash) {
|
||||
hashBits.setBit((hash & 0xFFFF) % NumBits);
|
||||
hashBits.setBit((hash >> 16) % NumBits);
|
||||
}
|
||||
bool isHashMaybeStored(uint hash) const {
|
||||
return hashBits.testBit((hash & 0xFFFF) % NumBits)
|
||||
&& hashBits.testBit((hash >> 16) % NumBits);
|
||||
}
|
||||
|
||||
private:
|
||||
QBitArray hashBits;
|
||||
};
|
||||
|
||||
class SocketListener {
|
||||
public:
|
||||
QIODevice* socket;
|
||||
|
||||
SocketListener(QIODevice* socket = 0) : socket(socket) { }
|
||||
|
||||
void sendMessage(const QString& message, bool doWait = false) const
|
||||
{
|
||||
DEBUG << "Sending message: " << message;
|
||||
QString localMessage = message;
|
||||
if( ! localMessage.endsWith(QLatin1Char('\n'))) {
|
||||
localMessage.append(QLatin1Char('\n'));
|
||||
}
|
||||
|
||||
QByteArray bytesToSend = localMessage.toUtf8();
|
||||
qint64 sent = socket->write(bytesToSend);
|
||||
if( doWait ) {
|
||||
socket->waitForBytesWritten(1000);
|
||||
}
|
||||
if( sent != bytesToSend.length() ) {
|
||||
qDebug() << "WARN: Could not send all data on socket for " << localMessage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sendMessageIfDirectoryMonitored(const QString& message, uint systemDirectoryHash) const
|
||||
{
|
||||
if (_monitoredDirectoriesBloomFilter.isHashMaybeStored(systemDirectoryHash))
|
||||
sendMessage(message, false);
|
||||
}
|
||||
|
||||
void registerMonitoredDirectory(uint systemDirectoryHash)
|
||||
{
|
||||
_monitoredDirectoriesBloomFilter.storeHash(systemDirectoryHash);
|
||||
}
|
||||
private:
|
||||
BloomFilter _monitoredDirectoriesBloomFilter;
|
||||
};
|
||||
|
||||
struct ListenerHasSocketPred {
|
||||
QIODevice *socket;
|
||||
ListenerHasSocketPred(QIODevice *socket) : socket(socket) { }
|
||||
bool operator()(const SocketListener &listener) const { return listener.socket == socket; }
|
||||
};
|
||||
|
||||
SocketApi::SocketApi(QObject* parent)
|
||||
: QObject(parent)
|
||||
@@ -129,7 +214,7 @@ SocketApi::~SocketApi()
|
||||
DEBUG << "dtor";
|
||||
_localServer.close();
|
||||
// All remaining sockets will be destroyed with _localServer, their parent
|
||||
Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
|
||||
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
||||
_listeners.clear();
|
||||
}
|
||||
|
||||
@@ -143,14 +228,16 @@ void SocketApi::slotNewConnection()
|
||||
DEBUG << "New connection" << socket;
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
||||
Q_ASSERT(socket->readAll().isEmpty());
|
||||
connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
|
||||
ASSERT(socket->readAll().isEmpty());
|
||||
|
||||
_listeners.append(socket);
|
||||
_listeners.append(SocketListener(socket));
|
||||
SocketListener &listener = _listeners.last();
|
||||
|
||||
foreach( Folder *f, FolderMan::instance()->map() ) {
|
||||
if (f->canSync()) {
|
||||
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
||||
sendMessage(socket, message);
|
||||
listener.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,32 +245,33 @@ void SocketApi::slotNewConnection()
|
||||
void SocketApi::onLostConnection()
|
||||
{
|
||||
DEBUG << "Lost connection " << sender();
|
||||
|
||||
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||
_listeners.removeAll(socket);
|
||||
socket->deleteLater();
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
void SocketApi::slotSocketDestroyed(QObject* obj)
|
||||
{
|
||||
QIODevice* socket = static_cast<QIODevice*>(obj);
|
||||
_listeners.erase(std::remove_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket)), _listeners.end());
|
||||
}
|
||||
|
||||
void SocketApi::slotReadSocket()
|
||||
{
|
||||
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
ASSERT(socket);
|
||||
SocketListener *listener = &*std::find_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket));
|
||||
|
||||
while(socket->canReadLine()) {
|
||||
// Make sure to normalize the input from the socket to
|
||||
// make sure that the path will match, especially on OS X.
|
||||
QString line = QString::fromUtf8(socket->readLine()).normalized(QString::NormalizationForm_C);
|
||||
line.chop(1); // remove the '\n'
|
||||
QString command = line.split(":").value(0);
|
||||
QString function = QString(QLatin1String("command_")).append(command);
|
||||
|
||||
QString functionWithArguments = function + QLatin1String("(QString,QIODevice*)");
|
||||
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
||||
QByteArray command = line.split(":").value(0).toAscii();
|
||||
QByteArray functionWithArguments = "command_" + command + "(QString,SocketListener*)";
|
||||
int indexOfMethod = staticMetaObject.indexOfMethod(functionWithArguments);
|
||||
|
||||
QString argument = line.remove(0, command.length()+1);
|
||||
if(indexOfMethod != -1) {
|
||||
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QIODevice*, socket));
|
||||
staticMetaObject.method(indexOfMethod).invoke(this, Q_ARG(QString, argument), Q_ARG(SocketListener*, listener));
|
||||
} else {
|
||||
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
||||
}
|
||||
@@ -199,8 +287,8 @@ void SocketApi::slotRegisterPath( const QString& alias )
|
||||
Folder *f = FolderMan::instance()->folder(alias);
|
||||
if (f) {
|
||||
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
||||
foreach(QIODevice *socket, _listeners) {
|
||||
sendMessage(socket, message);
|
||||
foreach (auto &listener, _listeners) {
|
||||
listener.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +302,7 @@ void SocketApi::slotUnregisterPath( const QString& alias )
|
||||
|
||||
Folder *f = FolderMan::instance()->folder(alias);
|
||||
if (f)
|
||||
broadcastMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null, true );
|
||||
broadcastMessage(buildMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null), true);
|
||||
|
||||
_registeredAliases.remove(alias);
|
||||
}
|
||||
@@ -235,74 +323,42 @@ void SocketApi::slotUpdateFolderView(Folder *f)
|
||||
f->syncResult().status() == SyncResult::SetupError ) {
|
||||
|
||||
QString rootPath = removeTrailingSlash(f->path());
|
||||
broadcastMessage(QLatin1String("STATUS"), rootPath,
|
||||
f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString());
|
||||
broadcastStatusPushMessage(rootPath, f->syncEngine().syncFileStatusTracker().fileStatus(""));
|
||||
|
||||
broadcastMessage(QLatin1String("UPDATE_VIEW"), rootPath);
|
||||
broadcastMessage(buildMessage(QLatin1String("UPDATE_VIEW"), rootPath));
|
||||
} else {
|
||||
qDebug() << "Not sending UPDATE_VIEW for" << f->alias() << "because status() is" << f->syncResult().status();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus)
|
||||
void SocketApi::broadcastMessage(const QString& msg, bool doWait)
|
||||
{
|
||||
broadcastMessage(QLatin1String("STATUS"), systemFileName, fileStatus.toSocketAPIString());
|
||||
}
|
||||
|
||||
void SocketApi::sendMessage(QIODevice *socket, const QString& message, bool doWait)
|
||||
{
|
||||
DEBUG << "Sending message: " << message;
|
||||
QString localMessage = message;
|
||||
if( ! localMessage.endsWith(QLatin1Char('\n'))) {
|
||||
localMessage.append(QLatin1Char('\n'));
|
||||
}
|
||||
|
||||
QByteArray bytesToSend = localMessage.toUtf8();
|
||||
qint64 sent = socket->write(bytesToSend);
|
||||
if( doWait ) {
|
||||
socket->waitForBytesWritten(1000);
|
||||
}
|
||||
if( sent != bytesToSend.length() ) {
|
||||
qDebug() << "WARN: Could not send all data on socket for " << localMessage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SocketApi::broadcastMessage( const QString& verb, const QString& path, const QString& status, bool doWait )
|
||||
{
|
||||
QString msg(verb);
|
||||
|
||||
if( !status.isEmpty() ) {
|
||||
msg.append(QLatin1Char(':'));
|
||||
msg.append(status);
|
||||
}
|
||||
if( !path.isEmpty() ) {
|
||||
msg.append(QLatin1Char(':'));
|
||||
QFileInfo fi(path);
|
||||
msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||
}
|
||||
|
||||
foreach(QIODevice *socket, _listeners) {
|
||||
sendMessage(socket, msg, doWait);
|
||||
foreach (auto &listener, _listeners) {
|
||||
listener.sendMessage(msg, doWait);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket)
|
||||
void SocketApi::broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus)
|
||||
{
|
||||
QString msg = buildMessage(QLatin1String("STATUS"), systemPath, fileStatus.toSocketAPIString());
|
||||
Q_ASSERT(!systemPath.endsWith('/'));
|
||||
uint directoryHash = qHash(systemPath.left(systemPath.lastIndexOf('/')));
|
||||
foreach (auto &listener, _listeners) {
|
||||
listener.sendMessageIfDirectoryMonitored(msg, directoryHash);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener)
|
||||
{
|
||||
// This command is the same as RETRIEVE_FILE_STATUS
|
||||
|
||||
//qDebug() << Q_FUNC_INFO << argument;
|
||||
command_RETRIEVE_FILE_STATUS(argument, socket);
|
||||
command_RETRIEVE_FILE_STATUS(argument, listener);
|
||||
}
|
||||
|
||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket)
|
||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener)
|
||||
{
|
||||
if( !socket ) {
|
||||
qDebug() << "No valid socket object.";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << argument;
|
||||
|
||||
QString statusString;
|
||||
@@ -312,27 +368,27 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice*
|
||||
// this can happen in offline mode e.g.: nothing to worry about
|
||||
statusString = QLatin1String("NOP");
|
||||
} else {
|
||||
QString relativePath = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1);
|
||||
if( relativePath.endsWith(QLatin1Char('/')) ) {
|
||||
relativePath.truncate(relativePath.length()-1);
|
||||
qWarning() << "Removed trailing slash for directory: " << relativePath << "Status pushes won't have one.";
|
||||
QString systemPath = QDir::cleanPath(argument);
|
||||
if( systemPath.endsWith(QLatin1Char('/')) ) {
|
||||
systemPath.truncate(systemPath.length()-1);
|
||||
qWarning() << "Removed trailing slash for directory: " << systemPath << "Status pushes won't have one.";
|
||||
}
|
||||
SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
|
||||
// The user probably visited this directory in the file shell.
|
||||
// Let the listener know that it should now send status pushes for sibblings of this file.
|
||||
QString directory = systemPath.left(systemPath.lastIndexOf('/'));
|
||||
listener->registerMonitoredDirectory(qHash(directory));
|
||||
|
||||
QString relativePath = systemPath.mid(syncFolder->cleanPath().length()+1);
|
||||
SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
|
||||
statusString = fileStatus.toSocketAPIString();
|
||||
}
|
||||
|
||||
const QString message = QLatin1String("STATUS:") % statusString % QLatin1Char(':') % QDir::toNativeSeparators(argument);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
}
|
||||
|
||||
void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener)
|
||||
{
|
||||
if (!socket) {
|
||||
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << localFile;
|
||||
|
||||
auto theme = Theme::instance();
|
||||
@@ -341,16 +397,16 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
if (!shareFolder) {
|
||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||
// files that are not within a sync folder are not synced.
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else if (!shareFolder->accountState()->isConnected()) {
|
||||
const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
|
||||
// if the folder isn't connected, don't open the share dialog
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else if (!theme->linkSharing() && (
|
||||
!theme->userGroupSharing() ||
|
||||
shareFolder->accountState()->account()->serverVersionInt() < ((8 << 16) + (2 << 8)))) {
|
||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else {
|
||||
const QString localFileClean = QDir::cleanPath(localFile);
|
||||
const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1);
|
||||
@@ -359,7 +415,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
// Verify the file is on the server (to our knowledge of course)
|
||||
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
||||
const QString message = QLatin1String("SHARE:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -368,7 +424,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
// Can't share root folder
|
||||
if (remotePath == "/") {
|
||||
const QString message = QLatin1String("SHARE:CANNOTSHAREROOT:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -382,31 +438,26 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||
}
|
||||
}
|
||||
const QString message = QLatin1String("SHARE:OK:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
|
||||
emit shareCommandReceived(remotePath, localFileClean, allowReshare);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_VERSION(const QString&, QIODevice* socket)
|
||||
void SocketApi::command_VERSION(const QString&, SocketListener* listener)
|
||||
{
|
||||
sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
||||
listener->sendMessage(QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
||||
}
|
||||
|
||||
void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket)
|
||||
void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* listener)
|
||||
{
|
||||
if (!socket) {
|
||||
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << localFile;
|
||||
|
||||
Folder *shareFolder = FolderMan::instance()->folderForPath(localFile);
|
||||
|
||||
if (!shareFolder) {
|
||||
const QString message = QLatin1String("SHARE_STATUS:NOP:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else {
|
||||
const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1);
|
||||
SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
||||
@@ -414,7 +465,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
|
||||
// Verify the file is on the server (to our knowledge of course)
|
||||
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
||||
const QString message = QLatin1String("SHARE_STATUS:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -422,7 +473,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
|
||||
|
||||
if (!capabilities.shareAPI()) {
|
||||
const QString message = QLatin1String("SHARE_STATUS:DISABLED:")+QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else {
|
||||
auto theme = Theme::instance();
|
||||
QString available;
|
||||
@@ -441,18 +492,18 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
|
||||
|
||||
if (available.isEmpty()) {
|
||||
const QString message = QLatin1String("SHARE_STATUS:DISABLED") + ":" + QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
} else {
|
||||
const QString message = QLatin1String("SHARE_STATUS:") + available + ":" + QDir::toNativeSeparators(localFile);
|
||||
sendMessage(socket, message);
|
||||
listener->sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, QIODevice* socket)
|
||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketListener* listener)
|
||||
{
|
||||
sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||
listener->sendMessage(QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||
}
|
||||
|
||||
QString SocketApi::buildRegisterPathMessage(const QString& path)
|
||||
|
||||
+11
-10
@@ -35,6 +35,7 @@ namespace OCC {
|
||||
|
||||
class SyncFileStatus;
|
||||
class Folder;
|
||||
class SocketListener;
|
||||
|
||||
/**
|
||||
* @brief The SocketApi class
|
||||
@@ -60,25 +61,25 @@ signals:
|
||||
private slots:
|
||||
void slotNewConnection();
|
||||
void onLostConnection();
|
||||
void slotSocketDestroyed(QObject* obj);
|
||||
void slotReadSocket();
|
||||
void slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus);
|
||||
void broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus);
|
||||
|
||||
private:
|
||||
void sendMessage(QIODevice* socket, const QString& message, bool doWait = false);
|
||||
void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
|
||||
void broadcastMessage(const QString& msg, bool doWait = false);
|
||||
|
||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket);
|
||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket);
|
||||
Q_INVOKABLE void command_SHARE(const QString& localFile, QIODevice* socket);
|
||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener);
|
||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener);
|
||||
Q_INVOKABLE void command_SHARE(const QString& localFile, SocketListener* listener);
|
||||
|
||||
Q_INVOKABLE void command_VERSION(const QString& argument, QIODevice* socket);
|
||||
Q_INVOKABLE void command_VERSION(const QString& argument, SocketListener* listener);
|
||||
|
||||
Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, QIODevice *socket);
|
||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QIODevice* socket);
|
||||
Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, SocketListener* listener);
|
||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, SocketListener* listener);
|
||||
QString buildRegisterPathMessage(const QString& path);
|
||||
|
||||
QSet<QString> _registeredAliases;
|
||||
QList<QIODevice*> _listeners;
|
||||
QList<SocketListener> _listeners;
|
||||
SocketApiServer _localServer;
|
||||
};
|
||||
|
||||
|
||||
@@ -145,18 +145,18 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
||||
|
||||
const QChar L = QLatin1Char('|');
|
||||
_out << ts << L;
|
||||
_out << QString::number(item._requestDuration) << L;
|
||||
if( item.log._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << L;
|
||||
if( item._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << item._file << L;
|
||||
} else {
|
||||
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
||||
}
|
||||
_out << instructionToStr( item.log._instruction ) << L;
|
||||
_out << instructionToStr( item._instruction ) << L;
|
||||
_out << directionToStr( item._direction ) << L;
|
||||
_out << QString::number(item.log._modtime) << L;
|
||||
_out << item.log._etag << L;
|
||||
_out << QString::number(item.log._size) << L;
|
||||
_out << item.log._fileId << L;
|
||||
_out << QString::number(item._modtime) << L;
|
||||
_out << item._etag << L;
|
||||
_out << QString::number(item._size) << L;
|
||||
_out << item._fileId << L;
|
||||
_out << item._status << L;
|
||||
_out << item._errorString << L;
|
||||
_out << QString::number(item._httpErrorCode) << L;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "updater/ocupdater.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include <QtGui>
|
||||
@@ -43,9 +44,8 @@ UpdaterScheduler::UpdaterScheduler(QObject *parent) :
|
||||
connect( &_updateCheckTimer, SIGNAL(timeout()),
|
||||
this, SLOT(slotTimerFired()) );
|
||||
|
||||
// Note: the sparkle-updater is not an OCUpdater and thus the dynamic_cast
|
||||
// returns NULL. Clever detail.
|
||||
if (OCUpdater *updater = dynamic_cast<OCUpdater*>(Updater::instance())) {
|
||||
// Note: the sparkle-updater is not an OCUpdater
|
||||
if (OCUpdater *updater = qobject_cast<OCUpdater*>(Updater::instance())) {
|
||||
connect(updater, SIGNAL(newUpdateAvailable(QString,QString)),
|
||||
this, SIGNAL(updaterAnnouncement(QString,QString)) );
|
||||
connect(updater, SIGNAL(requestRestart()), SIGNAL(requestRestart()));
|
||||
@@ -76,14 +76,17 @@ void UpdaterScheduler::slotTimerFired()
|
||||
return;
|
||||
}
|
||||
|
||||
Updater::instance()->backgroundCheckForUpdate();
|
||||
Updater *updater = Updater::instance();
|
||||
if (updater) {
|
||||
updater->backgroundCheckForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
OCUpdater::OCUpdater(const QUrl &url, QObject *parent) :
|
||||
QObject(parent)
|
||||
OCUpdater::OCUpdater(const QUrl &url) :
|
||||
Updater()
|
||||
, _updateUrl(url)
|
||||
, _state(Unknown)
|
||||
, _accessManager(new AccessManager(this))
|
||||
@@ -242,8 +245,8 @@ void OCUpdater::slotTimedOut()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NSISUpdater::NSISUpdater(const QUrl &url, QObject *parent)
|
||||
: OCUpdater(url, parent)
|
||||
NSISUpdater::NSISUpdater(const QUrl &url)
|
||||
: OCUpdater(url)
|
||||
, _showFallbackMessage(false)
|
||||
{
|
||||
}
|
||||
@@ -421,8 +424,8 @@ void NSISUpdater::slotSetSeenVersion()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url, QObject *parent)
|
||||
: OCUpdater(url, parent)
|
||||
PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url)
|
||||
: OCUpdater(url)
|
||||
{
|
||||
// remember the version of the currently running binary. On Linux it might happen that the
|
||||
// package management updates the package while the app is running. This is detected in the
|
||||
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
* @brief Class that uses an ownCloud proprietary XML format to fetch update information
|
||||
* @ingroup gui
|
||||
*/
|
||||
class OCUpdater : public QObject, public Updater
|
||||
class OCUpdater : public Updater
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
Downloading, DownloadComplete,
|
||||
DownloadFailed, DownloadTimedOut,
|
||||
UpdateOnlyAvailableThroughSystem };
|
||||
explicit OCUpdater(const QUrl &url, QObject *parent = 0);
|
||||
explicit OCUpdater(const QUrl &url);
|
||||
|
||||
bool performUpdate();
|
||||
|
||||
@@ -141,7 +141,7 @@ class NSISUpdater : public OCUpdater {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum UpdateState { NoUpdate = 0, UpdateAvailable, UpdateFailed };
|
||||
explicit NSISUpdater(const QUrl &url, QObject *parent = 0);
|
||||
explicit NSISUpdater(const QUrl &url);
|
||||
bool handleStartup() Q_DECL_OVERRIDE;
|
||||
private slots:
|
||||
void slotSetSeenVersion();
|
||||
@@ -167,7 +167,7 @@ private:
|
||||
class PassiveUpdateNotifier : public OCUpdater {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PassiveUpdateNotifier(const QUrl &url, QObject *parent = 0);
|
||||
explicit PassiveUpdateNotifier(const QUrl &url);
|
||||
bool handleStartup() Q_DECL_OVERRIDE { return false; }
|
||||
void backgroundCheckForUpdate() Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -87,6 +87,10 @@ Updater *Updater::create()
|
||||
if (updateBaseUrl.isEmpty()) {
|
||||
updateBaseUrl = QUrl(QLatin1String(APPLICATION_UPDATE_URL));
|
||||
}
|
||||
if (!updateBaseUrl.isValid() || updateBaseUrl.host() == ".") {
|
||||
qDebug() << "Not a valid updater URL, will not do update check";
|
||||
return 0;
|
||||
}
|
||||
updateBaseUrl = addQueryParams(updateBaseUrl);
|
||||
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
|
||||
updateBaseUrl.addQueryItem( QLatin1String("sparkle"), QLatin1String("true"));
|
||||
|
||||
@@ -21,7 +21,8 @@ class QUrl;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class Updater {
|
||||
class Updater : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct Helper {
|
||||
static qint64 stringVersionToInt(const QString& version);
|
||||
@@ -37,6 +38,7 @@ public:
|
||||
|
||||
protected:
|
||||
static QString clientVersion();
|
||||
Updater() : QObject(0) {}
|
||||
|
||||
private:
|
||||
static QString getSystemInfo();
|
||||
|
||||
@@ -68,6 +68,15 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
||||
_ui.lServerIcon->setPixmap(appIcon.pixmap(48));
|
||||
_ui.lLocalIcon->setText(QString());
|
||||
_ui.lLocalIcon->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/folder-sync.png")));
|
||||
|
||||
if (theme->wizardHideExternalStorageConfirmationCheckbox()) {
|
||||
_ui.confCheckBoxExternal->hide();
|
||||
}
|
||||
if (theme->wizardHideFolderSizeLimitCheckbox()) {
|
||||
_ui.confCheckBoxSize->hide();
|
||||
_ui.confSpinBox->hide();
|
||||
_ui.confTraillingSizeLabel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void OwncloudAdvancedSetupPage::setupCustomization()
|
||||
@@ -118,6 +127,12 @@ void OwncloudAdvancedSetupPage::initializePage()
|
||||
_selectiveSyncBlacklist = QStringList("/");
|
||||
QTimer::singleShot(0, this, SLOT(slotSelectiveSyncClicked()));
|
||||
}
|
||||
|
||||
ConfigFile cfgFile;
|
||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
_ui.confCheckBoxSize->setChecked(newFolderLimit.first);
|
||||
_ui.confSpinBox->setValue(newFolderLimit.second);
|
||||
_ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage());
|
||||
}
|
||||
|
||||
// Called if the user changes the user- or url field. Adjust the texts and
|
||||
@@ -200,6 +215,11 @@ QStringList OwncloudAdvancedSetupPage::selectiveSyncBlacklist() const
|
||||
return _selectiveSyncBlacklist;
|
||||
}
|
||||
|
||||
bool OwncloudAdvancedSetupPage::isConfirmBigFolderChecked() const
|
||||
{
|
||||
return _ui.rSyncEverything->isChecked() && _ui.confCheckBoxSize->isChecked();
|
||||
}
|
||||
|
||||
bool OwncloudAdvancedSetupPage::validatePage()
|
||||
{
|
||||
if(!_created) {
|
||||
@@ -208,6 +228,13 @@ bool OwncloudAdvancedSetupPage::validatePage()
|
||||
startSpinner();
|
||||
emit completeChanged();
|
||||
|
||||
if (_ui.rSyncEverything->isChecked()) {
|
||||
ConfigFile cfgFile;
|
||||
cfgFile.setNewBigFolderSizeLimit(_ui.confCheckBoxSize->isChecked(),
|
||||
_ui.confSpinBox->value());
|
||||
cfgFile.setConfirmExternalStorage(_ui.confCheckBoxExternal->isChecked());
|
||||
}
|
||||
|
||||
emit createLocalAndRemoteFolders(localFolder(), _remoteFolder);
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
bool validatePage() Q_DECL_OVERRIDE;
|
||||
QString localFolder() const;
|
||||
QStringList selectiveSyncBlacklist() const;
|
||||
bool isConfirmBigFolderChecked() const;
|
||||
void setRemoteFolder( const QString& remoteFolder);
|
||||
void setMultipleFoldersExist( bool exist );
|
||||
void directoriesCreated();
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>917</width>
|
||||
<height>493</height>
|
||||
<width>912</width>
|
||||
<height>633</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@@ -226,11 +226,14 @@
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rSyncEverything">
|
||||
<property name="text">
|
||||
@@ -263,6 +266,64 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="horizontalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="confCheckBoxSize">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchroni&zing folders larger than</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="confSpinBox">
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="confTraillingSizeLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="confCheckBoxExternal">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchronizing e&xternal storages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
@@ -345,5 +406,70 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confCheckBoxSize</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>217</x>
|
||||
<y>78</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>298</x>
|
||||
<y>126</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confSpinBox</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>311</x>
|
||||
<y>83</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>952</x>
|
||||
<y>134</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confTraillingSizeLabel</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>277</x>
|
||||
<y>76</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>1076</x>
|
||||
<y>136</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confCheckBoxExternal</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>181</x>
|
||||
<y>78</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>382</x>
|
||||
<y>174</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<height>193</height>
|
||||
<width>506</width>
|
||||
<height>515</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -80,7 +80,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Server &Address</string>
|
||||
<string>Ser&ver Address</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>leUrl</cstring>
|
||||
@@ -166,10 +166,13 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
||||
@@ -44,6 +44,7 @@ void OwncloudShibbolethCredsPage::setupBrowser()
|
||||
// i.e. if someone presses "back"
|
||||
QNetworkAccessManager *qnam = account->networkAccessManager();
|
||||
CookieJar *jar = new CookieJar;
|
||||
jar->restore(account->cookieJarPath());
|
||||
// Implicitly deletes the old cookie jar, and reparents the jar
|
||||
qnam->setCookieJar(jar);
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
||||
setTitleFormat(Qt::RichText);
|
||||
setSubTitleFormat(Qt::RichText);
|
||||
setButtonText(QWizard::CustomButton1, tr("Skip folders configuration"));
|
||||
|
||||
}
|
||||
|
||||
void OwncloudWizard::setAccount(AccountPtr account)
|
||||
@@ -109,6 +108,10 @@ QStringList OwncloudWizard::selectiveSyncBlacklist() const
|
||||
return _advancedSetupPage->selectiveSyncBlacklist();
|
||||
}
|
||||
|
||||
bool OwncloudWizard::isConfirmBigFolderChecked() const
|
||||
{
|
||||
return _advancedSetupPage->isConfirmBigFolderChecked();
|
||||
}
|
||||
|
||||
QString OwncloudWizard::ocUrl() const
|
||||
{
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
QString ocUrl() const;
|
||||
QString localFolder() const;
|
||||
QStringList selectiveSyncBlacklist() const;
|
||||
bool isConfirmBigFolderChecked() const;
|
||||
|
||||
void enableFinishOnResultWidget(bool enable);
|
||||
|
||||
|
||||
@@ -172,7 +172,6 @@ void AbstractNetworkJob::slotFinished()
|
||||
|
||||
// get the Date timestamp from reply
|
||||
_responseTimestamp = _reply->rawHeader("Date");
|
||||
_duration = _durationTimer.elapsed();
|
||||
|
||||
if (_followRedirects) {
|
||||
// ### the qWarnings here should be exported via displayErrors() so they
|
||||
@@ -206,11 +205,6 @@ void AbstractNetworkJob::slotFinished()
|
||||
}
|
||||
}
|
||||
|
||||
quint64 AbstractNetworkJob::duration()
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
{
|
||||
return _responseTimestamp;
|
||||
@@ -224,8 +218,6 @@ AbstractNetworkJob::~AbstractNetworkJob()
|
||||
void AbstractNetworkJob::start()
|
||||
{
|
||||
_timer.start();
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
qint64 timeoutMsec() { return _timer.interval(); }
|
||||
|
||||
@@ -82,8 +81,6 @@ protected:
|
||||
int maxRedirects() const { return 10; }
|
||||
virtual bool finished() = 0;
|
||||
QByteArray _responseTimestamp;
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is received
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "capabilities.h"
|
||||
#include "theme.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMutex>
|
||||
@@ -153,8 +154,9 @@ QUrl Account::davUrl() const
|
||||
*/
|
||||
void Account::clearCookieJar()
|
||||
{
|
||||
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
|
||||
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
|
||||
auto jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
||||
ASSERT(jar);
|
||||
jar->setAllCookies(QList<QNetworkCookie>());
|
||||
emit wantsAccountSaved(this);
|
||||
}
|
||||
|
||||
@@ -169,6 +171,12 @@ void Account::lendCookieJarTo(QNetworkAccessManager *guest)
|
||||
jar->setParent(oldParent); // takes it back
|
||||
}
|
||||
|
||||
QString Account::cookieJarPath()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies" + id() + ".db";
|
||||
}
|
||||
|
||||
void Account::resetNetworkAccessManager()
|
||||
{
|
||||
if (!_credentials || !_am) {
|
||||
|
||||
@@ -172,6 +172,7 @@ public:
|
||||
|
||||
void clearCookieJar();
|
||||
void lendCookieJarTo(QNetworkAccessManager *guest);
|
||||
QString cookieJarPath();
|
||||
|
||||
void resetNetworkAccessManager();
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef OWNCLOUD_ASSERTS_H
|
||||
#define OWNCLOUD_ASSERTS_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
|
||||
#define OC_ASSERT_MSG qFatal
|
||||
#else
|
||||
#define OC_ASSERT_MSG qWarning
|
||||
#endif
|
||||
|
||||
// For overloading macros by argument count
|
||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||
#define OC_ASSERT_CAT(A, B) A ## B
|
||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME ## _, NUM)
|
||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
||||
|
||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
// Default assert: If the condition is false in debug builds, terminate.
|
||||
//
|
||||
// Prints a message on failure, even in release builds.
|
||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||
#define ASSERT_1(cond) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ASSERT_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// Enforce condition to be true, even in release builds.
|
||||
//
|
||||
// Prints 'message' and aborts execution if 'cond' is false.
|
||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||
#define ENFORCE_1(cond) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ENFORCE_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// An assert that is only present in debug builds: typically used for
|
||||
// asserts that are too expensive for release mode.
|
||||
//
|
||||
// Q_ASSERT
|
||||
|
||||
#endif
|
||||
@@ -121,4 +121,13 @@ bool Capabilities::chunkingParallelUploadDisabled() const
|
||||
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
|
||||
}
|
||||
|
||||
QList<int> Capabilities::httpErrorCodesThatResetFailingChunkedUploads() const
|
||||
{
|
||||
QList<int> list;
|
||||
foreach (const auto & t, _capabilities["dav"].toMap()["httpErrorCodesThatResetFailingChunkedUploads"].toList()) {
|
||||
list.push_back(t.toInt());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -81,6 +81,25 @@ public:
|
||||
*/
|
||||
QByteArray uploadChecksumType() const;
|
||||
|
||||
/**
|
||||
* List of HTTP error codes should be guaranteed to eventually reset
|
||||
* failing chunked uploads.
|
||||
*
|
||||
* The resetting works by tracking UploadInfo::errorCount.
|
||||
*
|
||||
* Note that other error codes than the ones listed here may reset the
|
||||
* upload as well.
|
||||
*
|
||||
* Motivation: See #5344. They should always be reset on 412 (possibly
|
||||
* checksum error), but broken servers may also require resets on
|
||||
* unusual error codes such as 503.
|
||||
*
|
||||
* Path: dav/httpErrorCodesThatResetFailingChunkedUploads
|
||||
* Default: []
|
||||
* Example: [503, 500]
|
||||
*/
|
||||
QList<int> httpErrorCodesThatResetFailingChunkedUploads() const;
|
||||
|
||||
private:
|
||||
QVariantMap _capabilities;
|
||||
};
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário