Comparar commits

..

103 Commits

Autor SHA1 Mensagem Data
Klaas Freitag e95b73dfac Avatar: Set a circle mask around the avatar image.
The server displays the avatar cut into a circle, and so we do.
2017-01-23 21:36:18 +01:00
Klaas Freitag c00e3e8c0a ConnectionValidator: Set a 20 second timeout for Avatar request. 2017-01-23 21:35:12 +01:00
Klaas Freitag 2a12610a46 Update ASCII-Art describing the connection check flow.
Added Avatar fetching
2017-01-23 21:34:34 +01:00
Klaas Freitag d466a05915 SettingsDialog: Display the user avatar as action icon if available.
The avatar image is fetched from the server async, thus connect a signal
from the account if the avatar changes.

Server feature https://github.com/owncloud/core/pull/26872 is needed.
2017-01-22 13:58:36 +01:00
Klaas Freitag e05d6bfcdc Make the Account store the avatar pixmap.
The avatar pixmap is fetched from the server by the Connectionvalidator,
once it has validated the user name, it queries the avatar pixmap.

If the server does not have the avatar route, an empty pixmap is stored.
2017-01-22 13:55:08 +01:00
Klaas Freitag b49dd02e3d New network job AvatarJob: GETs the account avatar from server. 2017-01-22 13:52:19 +01:00
Olivier Goffart d6fdda8efa ChunkingNG: add '0' padding on the filename (#5476)
The server sorts the chunk by name alphabetically. So if we want to keep
the chunk in order, we need to add a few '0' in front of the chunk name
2017-01-20 16:03:50 +01:00
Markus Goetz faedaa5e09 Update issue_template.md 2017-01-20 16:00:50 +01:00
Jenkins for ownCloud 661c7f0558 [tx-robot] updated from transifex 2017-01-20 02:18:34 +01:00
Jenkins for ownCloud a7efe144fc [tx-robot] updated from transifex 2017-01-19 02:18:40 +01:00
Jocelyn Turcotte b68a28de8d StatusTracker: Emit OK for the last child before parents (#5467)
The current logic tried to avoid a DB lookup just to fetch whether
the file is shared or not since that info is already in the
SyncFileItem. The implementation would however need to decrease the
sync count for itself (and parents) before emitting the new status,
thus emitting the OK status for parents before that last child that
ended the propagation for that folder.

Change the implementation to achieve what we want: give the
possibility to decSyncCount to use a pre-fetched sharing state while
still doing the emission for all involved files. This ensures that
the leaf file also gets its status emitted before its parents.

Issue #4797
2017-01-18 15:40:52 +01:00
Samuel Alfageme 72a7b7ca42 Reference to build Qt5 with qtwebkit support in the docs #5129 (#5471)
This addresses the issue only on OS X. It should be stated though, that qtwebkit is not part of the qt5core lib and therefore a requirement for the projectto build in the rest of the OSS
2017-01-18 14:46:47 +01:00
Jocelyn Turcotte 166ef85a51 shell/Windows: Update binaries to build 44 2017-01-18 13:34:02 +01:00
Matthew Setter 1f60c61f87 Update the MacOS automatic update instructions
As requested in #5431, the automatic update instructions for MacOS X
have been simplified; removing the older, incorrect instructions.
2017-01-18 12:55:23 +01:00
Matthew Setter 30ef794fa1 Fix several typos in the client documentation 2017-01-18 12:53:33 +01:00
Jocelyn Turcotte 47fbfbc006 shell/Windows: Avoid memory allocations and copies when querying icons
IsMemberOf is called for every file (in the ownCloud directory or not) and
with every instance of OCOverlay (we have 5) when displaying a list of
files in Explorer.

Refactor the code to avoid copying the list of watched directories, as
well as creating a wstring from a PWWSTR for files outside watched
directories.

Also change some calls of begin_with to use isDescendantOf since it
properly handles parent paths not ending with a backslash, which could
lead to SocketAPI queries for sibling folders with a name that starts with
a watched folder name.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte e131c142ff shell/Windows: Fix the view not being updated on StateError
Since StateError == 0, if this was the status used when the path
isn't in the map already, the view would not be updated since the
new state would be the same as the default-constructed state in the
map. Fix by explicitly inserting in that case, this also avoid aving
to do two lookups in the map when a path already has an entry.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte 1b99ff2e91 shell/Windows: Remove the UPDATE_VIEW message handling
The client now tries to only push STATUS messages to connections
unless they previously requested it with a RETRIEVE_FILE_STATUS,
but this means that we now have to make sure that a new connection
will rerequest every icon that the user will see on files from that
point on.

To that end, we now send a SHChangeNotify for every file in the cache
when we lose the connection (or on UNREGISTER_PATH) to make sure that
what's on the screen matches what's in the cache. We also remove the
_oldCache logic that made this more difficult to enforce.

The client has been able to reliably push status updates on macOS
for a few versions now, and we don't need it on Windows either. The
_oldCache mechanism was to avoid sending to many update requests
when receiving an UPDATE_VIEW.

Also fixes #4766
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte 3e85d47a57 shell/Windows: Convert tabs to space
It was a mix of both and the rest of the code uses spaces.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte e709d75d56 shell/Windows: Remove unused files
The real OCContextMenu.cpp is in the OCContextMenu folder.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte cb5cfb8cf6 shell/macOS: Make sure the root folder's cache is cleared on disconnect
The SocketAPI now only sends status pushes for paths requested by the
shell. We have to make sure that Finder doesn't just show the entry
from its cache after a reconnect.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte ebd2a15711 shell/macOS: Remove backslashes from the extension display name
Tell cmake not to escape shell strings adding backslashes before
spaces by passing the VERBATIM optiton. Also add the quotes to
whole command line arguments to prevent quotes from appearing on the
XCode side, because of the VERBATIM option.

This only affects themed clients since the default theme doesn't
have space in its APPLICATION_NAME.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte d3a0608bd5 SocketAPI: Only push status for files requested by the shell #5361
We currently push the SYNC status for all files that will be propagated,
and then the OK status when those files are propagated.
On top of this, we send those statuses to all clients connected, even
if the socket is kept open by an application that only needed to show
a file open dialog. On macOS we're also using an NSConnection which
means that we have to wait for the RPC call to return from the
extension, which makes bulk status changes possibly heavy.

Reduce the time spent needlessly sending status pushes by limiting
them to files requested through that socket since it connected.
To limit the data to store, only remember the parent directory of
files requested, and store those in a bloom filter.

Note that this adds a requirement to shell extensions: they should
make sure that the status cache only contains entries that have been
requested through the socket API. In other words, the status cache
must be empty when each socket client connects to the socket API.
Otherwise the cached icon type will be shown to the user, and the
SocketAPI won't push new status for that file if it didn't receive
a RETRIEVE_FILE_STATUS.
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte c25b599bbb SocketApi::slotReadSocket: Small optimizations
- Use the looked-up method index also for the invocation
- Do the method name concatenation already on QByteArray since we'll
  convert anyway
- Use staticMetaObject instead of metaObject()
2017-01-18 12:15:52 +01:00
Jocelyn Turcotte a5ff9e58e3 SocketAPI: Remove unecessary null-checks
Those methods are private and there is only one call-site, we can
be sure that this parameter won't be null already.
2017-01-18 12:15:52 +01:00
Olivier Goffart 9b96899d75 Sync Engine: Specify what chars are not syncable in the error message #1733 (#5449) 2017-01-18 11:45:46 +01:00
Olivier Goffart b046cca010 Fix more compilation errors with Qt 4
Ammand last commit which was a fixup to the change from pull request #5468
for issue #5453
2017-01-18 10:19:51 +01:00
Olivier Goffart edf0a99a8a Fix compilation with Qt 4
Fixup to the change from pull request #5468 for issue #5453
2017-01-18 09:57:36 +01:00
Jenkins for ownCloud a4640b202f [tx-robot] updated from transifex 2017-01-18 02:18:27 +01:00
Markus Goetz 5ef2e88f00 NSIS: Adjust to 5.6.2 image 2017-01-17 17:35:32 +01:00
Christian Kamm 352f168313 Folder: Remove unused variable 2017-01-17 14:53:09 +01:00
Markus Goetz 85d3de1589 Disable RTTI
Shrinks owncloud binary by 24 KB and libowncloudsync by 14 KB.
I don't know if it has influence on memory usage or runtime speed though.

Was worth a try.
2017-01-17 14:52:10 +01:00
Markus Goetz 588a88fb63 Updater: Don't create instance for invalid URL
Also don't use dynamic_cast
For enterprise/#689
2017-01-17 14:52:10 +01:00
Christian Kamm cd9e88ad22 PropagatorJob: Remove unneccessary pointer #5453 2017-01-17 14:47:38 +01:00
Christian Kamm 29b39acfbe PropagatorJob: Access propagator through function #5453 2017-01-17 14:47:38 +01:00
Matthew Setter 7427be0062 Merge pull request #5466 from settermjd/add-directory-limit-to-faq
Add Sync Client's Directory Depth Limit To FAQ
2017-01-17 14:33:35 +01:00
Matthew Setter e7546903cc Add an FAQ entry about the sync client's sub-directory scan limit
As requested in #1067, this commit adds an entry to the FAQ to highlight
the fact that the sync client will never scan greater than 50
sub-directories.
2017-01-17 11:14:52 +01:00
Matthew Setter 78e3a7e897 Revise the FAQ entry style
This approach uses less content, and makes the content more prominent.
2017-01-17 10:36:42 +01:00
Jenkins for ownCloud 1a21b8698e [tx-robot] updated from transifex 2017-01-17 02:18:34 +01:00
Carlos Damken 280906eab9 Ignoring "System Volume Information"
Avoid to upload the "System Volume Information"
2017-01-16 19:11:56 +01:00
Markus Goetz 9d7425b201 DB: Also migrate -shm and -wal to new name #3764 #5045 (#5459) 2017-01-16 15:42:11 +01:00
Markus Goetz 7eb43d7f7e PropagateUploadFileNG: Delete unused map contents to free memory 2017-01-13 19:00:04 +01:00
ckamm d76e0ec6d8 Reset stuck chunked uploads eventually #5344 (#5443)
Previously this wasn't happening for errors that were not
NormalErrors because they don't end up in the blacklist.

This revises the resetting logic to be independent of the
error blacklist and make use of UploadInfo::errorCount
instead.

412 errors should reset chunked uploads because they might be
indicative of a checksum error.

Additionally, server bugs might require that additional
errors cause an upload reset. To allow that, a new capability
is added that can be used to advise the client about this.
2017-01-13 14:44:45 +01:00
Jenkins for ownCloud 4a83f976e1 [tx-robot] updated from transifex 2017-01-13 02:18:27 +01:00
Jenkins for ownCloud 23572aaf77 [tx-robot] updated from transifex 2017-01-12 02:18:33 +01:00
Christian Kamm 48655ff1ec Doc: Add forceSyncInterval and timeout config file flags 2017-01-11 11:34:36 +01:00
Christian Kamm ffbf34cb97 Log the auth type being used for accounts
There have been hard to track down bugs related to the wrong auth
type being used.
2017-01-11 09:30:59 +01:00
Jenkins for ownCloud fad690be11 [tx-robot] updated from transifex 2017-01-11 02:18:38 +01:00
Jenkins for ownCloud 355a644020 [tx-robot] updated from transifex 2017-01-10 02:18:34 +01:00
Jenkins for ownCloud 5e6e4e7464 [tx-robot] updated from transifex 2017-01-08 02:18:35 +01:00
Markus Goetz 76fde49282 sqlite: Update bundled version to 3.16.1
For OS X and Windows.
2017-01-05 17:27:46 +01:00
Markus Goetz 4ef7d0410d First iteration ChangeLog for 2.3.0 2017-01-05 16:56:37 +01:00
octotree a1b4984d14 Symlink Support for Dolphin Plugins (#5428)
Add Symlink Support to Dolphin Overlay Plugin
2017-01-05 13:24:22 +01:00
Christian Kamm adbe5ecf55 ownsql: qFatal on prepare errors #5357 2017-01-04 15:15:06 +01:00
Jenkins for ownCloud ba32571039 [tx-robot] updated from transifex 2017-01-04 02:19:32 +01:00
Christian Kamm 084146756b Account: Fix displayName() #5413
This displayName() seemed to be based on Account::user() which used
to call _credentials->user(). But then we repurposed user() to be
davUser() and this usage wasn't updated to point back to the username
used for the credentials.
2017-01-03 13:54:59 +01:00
ckamm e1f5a49c21 Don't blacklist 507 Insufficent Storage #5346 (#5424) 2017-01-03 13:48:32 +01:00
ckamm 143320341e Build: Enable Q_ASSERT in release mode (#5425) 2017-01-03 13:42:25 +01:00
Christian Kamm e286bb1b64 Wizard: Don't accidentally pre-fill url field #5412
slotUrlEditFinished() is called when the wizard is triggered in
some situations.
2017-01-03 11:53:40 +01:00
Olivier Goffart d433f0e08e HTTPCreds: remove all cookies when logging out (#5383)
Some custom server use persistent cookies with the auth token. So we should
clear all the cookies when disconnecting.
Account::clearCookieJar is only called from the HTTPCredentials. This funciton
is not used for shibboleth.
There is probably no reasons to keep the HTTP cookie anyway.

Issue #5370
2017-01-03 11:39:10 +01:00
Christian Kamm 107149d601 Doc: Improve example #5422 2017-01-03 11:31:51 +01:00
Christian Kamm fa9b36f829 Wizard: Let the user know if url is invalid #5398 2017-01-03 11:28:56 +01:00
Christian Kamm 6775292d63 Fix compile of tests 2017-01-03 10:52:39 +01:00
Christian Kamm 6835429a28 Sql: Allow prepare fail for PRAGMA quick_check #5357
This actually happens in low-disk situations.
2017-01-03 10:43:29 +01:00
Christian Kamm 22135f9f57 Fixup broken authType on load #5408 2017-01-03 10:38:20 +01:00
Jenkins for ownCloud 0fd06a225c [tx-robot] updated from transifex 2017-01-03 02:19:30 +01:00
Christian Kamm 473dcb0947 Only create a FolderWatcher if the path exists
Also retry creating it before each sync.

See #5317
2017-01-02 08:52:26 +01:00
Christian Kamm e306f4611c Reschedule a folder regularly with some delay for some errors
Like "folder doesn't exist" - such that we will detect when the folder
becomes available and start syncing.

See #5317
2017-01-02 08:52:26 +01:00
Markus Goetz c6f4f44619 Fix up SSL client certificates #5213 #69 (#5289)
The re-enables the UI, uses Qt API for importing and
stores the certificate/key in the system keychain.
People who had set up client certs need to re-setup the account. This is ok
since it was an undocumented feature anyway.
2017-01-02 08:34:02 +01:00
Jenkins for ownCloud 0865c63745 [tx-robot] updated from transifex 2017-01-02 02:19:26 +01:00
Jenkins for ownCloud b81c3a6a67 [tx-robot] updated from transifex 2017-01-01 02:19:32 +01:00
Jenkins for ownCloud cc56e5639d [tx-robot] updated from transifex 2016-12-30 02:18:34 +01:00
Jenkins for ownCloud 3ce5b358ae [tx-robot] updated from transifex 2016-12-25 02:18:27 +01:00
Jenkins for ownCloud e968284618 [tx-robot] updated from transifex 2016-12-24 02:18:26 +01:00
Jenkins for ownCloud c7723179d8 [tx-robot] updated from transifex 2016-12-23 02:18:34 +01:00
Jenkins for ownCloud 1872f3f94a [tx-robot] updated from transifex 2016-12-22 02:18:30 +01:00
Christian Kamm 3b7887ca35 Wizard: Detach saved account from wizard
Fixes #5408 #5407.

The problem was that cleanup of the credentials page set the
credentials of the account back to dummy, thereby overriding
things like shib usernames.

This should be broken since a932eac832.
2016-12-21 15:31:12 +01:00
Piotr Mrówczyński d781e63fab Add capability to disable parallel chunked upload #5364 - technical review (#5403) 2016-12-21 15:08:45 +01:00
Kyle Fazzari d1237cdda3 Correctly handle possible missing GIT_SHA1. (#5401)
Currently, if get_git_head_revision() doesn't define GIT_SHA1 (which it
doesn't in some cases) it's possible to end up with the following error:

    CMake Error at CMakeLists.txt:69 (if):
      if given arguments:

        "STREQUAL" "GITDIR-NOTFOUND"

      Unknown arguments specified

Fix this by making sure both left and right hand arguments to STREQUAL
are always strings, even if GIT_SHA1 is undefined.

Signed-off-by: Kyle Fazzari <kyle@canonical.com>
2016-12-21 14:14:26 +01:00
Christian Kamm 030e3a5d4a Increase initial bandwidth estimates #4428 #5390
To 2 MB/s and 10 files/s.
2016-12-21 08:53:47 +01:00
Jenkins for ownCloud 4fa4a6a5ed [tx-robot] updated from transifex 2016-12-21 02:18:28 +01:00
Phil Davis 23fb07240b Fix Mac PATH command
Reported in the doc repo owncloud/documentation#1618
This version as suggested by @jturcotte
2016-12-20 20:01:38 +01:00
Christian Kamm 3912dba33a Move qDeclareMetatype from Folder to SyncEngine 2016-12-20 11:43:39 +01:00
Christian Kamm d8c479ab1e Don't wipe db if check fails while disk space is low #5357
An experimental fix for the issue, merged because it's low risk and
makes testing easier.
2016-12-20 09:33:59 +01:00
Jenkins for ownCloud bec67455c1 [tx-robot] updated from transifex 2016-12-20 02:18:27 +01:00
Jenkins for ownCloud ba6a37a601 [tx-robot] updated from transifex 2016-12-19 02:18:28 +01:00
Jenkins for ownCloud 03f5091e73 [tx-robot] updated from transifex 2016-12-18 02:18:28 +01:00
Jenkins for ownCloud 6b6ff08821 [tx-robot] updated from transifex 2016-12-17 02:18:27 +01:00
Jenkins for ownCloud 35a0ee4893 [tx-robot] updated from transifex 2016-12-16 02:18:29 +01:00
Jenkins for ownCloud 3519391119 [tx-robot] updated from transifex 2016-12-15 02:18:37 +01:00
Olivier Goffart 775a1c9ad8 FolderStatusModel: Fix insert/remove items when there are labels
Otherwise it might happen that the model is inconsistant and this can
lead to crash in the worst case.

(For example, if there was a "fetching" label, and we hide it because it
was a 404. In this case, we would not call begin/endRemoveRows, so the
view could still call the model with an index of row 0, that used to be
for the label, but now correspond to the first element of _subs. And
because _subs is empty, this could lead to crashes)
2016-12-14 14:13:47 +01:00
Olivier Goffart ac95844ebd Propagator: make sure every network job has a parent
This could make sure that the network job gets deleted if the parent job gets
deleted, and would avoid crashes like:

Crash: EXCEPTION_ACCESS_VIOLATION_READ at 0xffffffff8b008a04
  File "qiodevice.cpp", line 1617, in QIODevice::errorString
  File "propagatedownload.cpp", line 264, in OCC::GETFileJob::slotReadyRead
  File "moc_propagatedownload.cpp", line 85, in OCC::GETFileJob::qt_static_metacall
  File "qobject.cpp", line 3716, in QMetaObject::activate
  File "moc_qiodevice.cpp", line 154, in QIODevice::readyRead
  File "qnetworkreplyhttpimpl.cpp", line 1045, in QNetworkReplyHttpImplPrivate::replyDownloadData

(#5329)
2016-12-14 14:13:47 +01:00
Olivier Goffart c5b90d9507 Account::slotHandleSslErrors: add guards in case the reply gets deleted in the dialog event loop
Since slotHandleSslErrors will show a dialog with an eventloop, it could be
That the reply gets deleted. Guard against that.

(#5329)
2016-12-14 14:13:47 +01:00
Christian Kamm d631f2e070 Sync now: Disable on disconnect, rename while running #2158 2016-12-13 15:28:52 +01:00
Jonathan Kawohl 5bae2ed5ef fixed merge conflicts 2016-12-13 09:12:50 +01:00
Jenkins for ownCloud 5af2a657ca [tx-robot] updated from transifex 2016-12-13 02:18:28 +01:00
Jenkins for ownCloud 71231026a0 [tx-robot] updated from transifex 2016-12-12 02:18:28 +01:00
Jenkins for ownCloud dfca67b63a [tx-robot] updated from transifex 2016-12-11 02:18:27 +01:00
Jenkins for ownCloud 7dc6a3b89f [tx-robot] updated from transifex 2016-12-10 02:18:32 +01:00
Jocelyn Turcotte f985111b62 Fix the log window not showing csync logs
The csync log level was only set up on startup, and for log files.
Fix the issue by making Logger::isNoop rely on being explicitly activated
for the log window instead of relying on the presence of a connected
signal, and move the csync log level logic in Logger.
2016-12-09 10:03:46 +01:00
Jocelyn Turcotte e8d734b1c2 Fix the sync direction being wrong on MSVC
The compiler seems to use signed enums and we need to reserve an extra
bit for the sign to avoid the 2 value to overflow and being interpreted
as -2 when read, and thus not being correctly compared to the full enum
value.
2016-12-09 10:03:46 +01:00
Jenkins for ownCloud a38864fcb4 [tx-robot] updated from transifex 2016-12-09 02:18:28 +01:00
Jenkins for ownCloud 47bab51474 [tx-robot] updated from transifex 2016-12-08 02:18:27 +01:00
157 arquivos alterados com 17818 adições e 13960 exclusões
+4 -1
Ver Arquivo
@@ -58,6 +58,9 @@ if( UNIX AND NOT APPLE )
endif()
####
# Enable Q_ASSERT etc. in all builds
add_definitions( -DQT_FORCE_ASSERTS )
include(GNUInstallDirs)
include(DefineInstallationPaths)
include(GenerateExportHeader)
@@ -69,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
# if we cannot get it from git, directly try .tag (packages)
# this will work if the tar balls have been properly created
# via git-archive.
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
+39
Ver Arquivo
@@ -1,6 +1,45 @@
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
* 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)
* Conflicts: Use the local mtime for the conflict file name (#5273)
* "Sync now" menu item
* SSL Client certificate support improved (Show UI, Store keys in keychain)
* Propagator: Upload more small files in parallel
* Sync Engine: Read data-fingerprint property to detect backups (#2325)
* GUI: Show link to ceate an app password/token for syncing
* Share dialog: Add 'Mail link' button
* Caja file manager plugin
* Make "backup detected" message to not trigger in wrong cases
* SyncEngine: Fix renaming of folder when file are changed (#5192)
* Fix reconnect bug if status.php intermittently returns wrong data (#5188)
* Improve sync scheduling (#5317)
* Overlay icons: Improvements in correctnes
* Tray menu: Only update on demand to fix Linux desktop integration glitches
* Progress: Better time/bandwidth estimations
* Network: Follow certain HTTP redirects (#2791)
* Network: Remove all cookies (including load balancers etc) when logging out
* Discovery thread: Low priority
* owncloudsync.log: Write during propagation
* Better error message for files with trailing spaces on Windows
* Excludes: Consider files in hidden folders excluded (#5163)
* Allow sync directory to be a symlinked directory
* Add manifest file on Windows to make the application UAC aware
* macOS: Improve monochrome tray icons
* Don't blacklist 507 Insufficent Storage #5346 (#5424)
* Shibboleth bugfixes
* Fixes with regards to low disk space
* A ton of other bugfixes
* Refactorings
* Improved documentation
* Crash fixes
version 2.2.4 (release 2016-09-27)
* Dolphin Plugin: Use the Application name for the socket path (#5172)
* SyncEngine: Fix renaming of folder when file are changed (#5195)
+1 -1
Submodule binary updated: 0d89ac7766...741b49156b
+8 -7
Ver Arquivo
@@ -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"
-5
Ver Arquivo
@@ -44,11 +44,6 @@
extern "C" {
#endif
struct csync_client_certs_s {
char *certificatePath;
char *certificatePasswd;
};
enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
-3
Ver Arquivo
@@ -103,9 +103,6 @@ struct csync_s {
} callbacks;
c_strlist_t *excludes;
// needed for SSL client certificate support
struct csync_client_certs_s *clientCerts;
struct {
char *file;
+1 -1
Ver Arquivo
@@ -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
+3 -20
Ver Arquivo
@@ -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``.
+13 -17
Ver Arquivo
@@ -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
@@ -68,42 +68,38 @@ To set up your build environment for development using HomeBrew_:
1. Install Xcode
2. Install Xcode command line tools::
<<<<<<< HEAD
xcode-select --install
3. Install homebrew::
=======
xcode-select --install
3. Install homebrew::
>>>>>>> ca9ec4625391ae23940b3a62aaa0afe89f3d98e8
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
4. Add the ownCloud repository using the following command::
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/qmake
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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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.
+1 -1
Ver Arquivo
@@ -65,7 +65,7 @@ If no client is configured, or if you choose to use a different user to synchron
you can specify the user
password setting with the usual URL pattern. For example::
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
$ owncloudcmd /home/user/my_sync_folder https://carla:secret@server/owncloud/remote.php/webdav/
To synchronize the ownCloud directory ``Music`` to the local directory
``media/music``, through a proxy listening on port ``8080``, and on a gateway
+2 -2
Ver Arquivo
@@ -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
+4
Ver Arquivo
@@ -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
+96
Ver Arquivo
@@ -553,6 +553,99 @@ 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
# Translations
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
GenericName[oc]=Dorsièr de Sincronizacion
@@ -688,7 +781,10 @@ Comment[th_TH]=@APPLICATION_NAME@ ไคลเอนต์ประสานข
GenericName[th_TH]=ประสานข้อมูลโฟลเดอร์
Name[th_TH]= @APPLICATION_NAME@ ไคลเอนต์ประสานข้อมูลเดสก์ท็อป
Icon[th_TH]=@APPLICATION_EXECUTABLE@
Comment[es_MX]=Cliente de escritorio para sincronziación de @APPLICATION_NAME@
GenericName[es_MX]=Sincronización de Carpetas
Name[es_MX]=Cliente de escritorio para sincronziación de @APPLICATION_NAME@
Icon[es_MX]=@APPLICATION_EXECUTABLE@
Comment[nb_NO]=@APPLICATION_NAME@ skrivebordssynkroniseringsklient
GenericName[nb_NO]=Mappesynkronisering
Name[nb_NO]=@APPLICATION_NAME@ skrivebordssynkroniseringsklient
+7 -6
Ver Arquivo
@@ -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;
}
@@ -24,6 +24,7 @@
#include <KIOCore/kfileitem.h>
#include <KIOCore/KFileItemListProperties>
#include <QtWidgets/QAction>
#include <QtCore/QDir>
#include <QtCore/QTimer>
#include "ownclouddolphinpluginhelper.h"
@@ -43,7 +44,8 @@ public:
auto url = urls.first();
if (!url.isLocalFile())
return {};
auto localFile = url.toLocalFile();
QDir localPath(url.toLocalFile());
auto localFile = localPath.canonicalPath();
const auto paths = helper->paths();
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
@@ -21,6 +21,7 @@
#include <KPluginFactory>
#include <QtNetwork/QLocalSocket>
#include <KIOCore/kfileitem.h>
#include <QDir>
#include <QTimer>
#include "ownclouddolphinpluginhelper.h"
@@ -46,7 +47,8 @@ public:
return QStringList();
if (!url.isLocalFile())
return QStringList();
const QByteArray localFile = url.toLocalFile().toUtf8();
QDir localPath(url.toLocalFile());
const QByteArray localFile = localPath.canonicalPath().toUtf8();
helper->sendCommand(QByteArray("RETRIEVE_FILE_STATUS:" + localFile + "\n"));
@@ -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
+94 -94
Ver Arquivo
@@ -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
+57 -72
Ver Arquivo
@@ -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;
};
+41 -41
Ver Arquivo
@@ -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;
}
+7 -7
Ver Arquivo
@@ -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
+21 -21
Ver Arquivo
@@ -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;
}
+7 -7
Ver Arquivo
@@ -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
+247 -247
Ver Arquivo
@@ -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;
}
+28 -28
Ver Arquivo
@@ -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;
}
+4 -4
Ver Arquivo
@@ -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();
};
+7 -7
Ver Arquivo
@@ -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);
}
+23 -8
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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)
-110
Ver Arquivo
@@ -1,110 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* \file p12topem.cpp
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include "p12topem.h"
/**
* \fn string x509ToString (BIO)
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o) {
BUF_MEM *bptr;
BIO_get_mem_ptr(o, &bptr);
int len = bptr->length;
void* data = calloc(len+10, sizeof(char));
BIO_read(o, data, len);
string ret = std::string(static_cast<char*>(data));
free(data);
return ret;
}
/**
* \fn resultP12ToPem p12ToPem (string, string)
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd) {
FILE *fp;
PKCS12 *p12 = NULL;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
STACK_OF(X509) *ca = NULL;
BIO *o = BIO_new(BIO_s_mem());
string privateKey = "";
string certificate = "";
resultP12ToPem ret;
ret.ReturnCode = false;
ret.ErrorCode = 0;
ret.Comment = "";
ret.PrivateKey = "";
ret.Certificate = "";
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
if(!(fp = fopen(p12File.c_str(), "rb"))) {
ret.ErrorCode = 1;
ret.Comment = strerror(errno);
return ret;
}
p12 = d2i_PKCS12_fp(fp, &p12);
fclose (fp);
if (!p12) {
ret.ErrorCode = 2;
ret.Comment = "Unable to open PKCS#12 file";
return ret;
}
if (!PKCS12_parse(p12, p12Passwd.c_str(), &pkey, &cert, &ca)) {
ret.ErrorCode = 3;
ret.Comment = "Unable to parse PKCS#12 file (wrong password ?)";
return ret;
}
PKCS12_free(p12);
if (!(pkey && cert)) {
ret.ErrorCode = 4;
ret.Comment = "Certificate and/or key file doesn't exists";
} else {
PEM_write_bio_PrivateKey(o, pkey, 0, 0, 0, NULL, 0);
privateKey = x509ToString(o);
PEM_write_bio_X509(o, cert);
certificate = x509ToString(o);
BIO_free(o);
ret.ReturnCode = true;
ret.ErrorCode = 0;
ret.Comment = "All is fine";
ret.PrivateKey = privateKey;
ret.Certificate = certificate;
}
return ret;
}
-62
Ver Arquivo
@@ -1,62 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef P12TOPEM_H
#define P12TOPEM_H
/**
* \file p12topem.h
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
using namespace std;
/**
* \struct resultP12ToPem p12topem.h
*/
struct resultP12ToPem {
bool ReturnCode;
int ErrorCode;
string Comment;
string PrivateKey;
string Certificate;
};
/**
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o);
/**
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd);
#endif /* P12TOPEM_H */
+6941 -4159
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+125 -29
Ver Arquivo
@@ -108,7 +108,8 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
** Since version 3.6.18, SQLite source code has been stored in the
** Since [version 3.6.18] ([dateof:3.6.18]),
** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
@@ -120,13 +121,13 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.14.2"
#define SQLITE_VERSION_NUMBER 3014002
#define SQLITE_SOURCE_ID "2016-09-12 18:50:49 29dbef4b8585f753861a36d6dd102ca634197bd6"
#define SQLITE_VERSION "3.16.1"
#define SQLITE_VERSION_NUMBER 3016001
#define SQLITE_SOURCE_ID "2017-01-03 18:27:03 979f04392853b8053817a3eea2fc679947b437fd"
/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -452,7 +453,8 @@ SQLITE_API int sqlite3_exec(
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** address this, newer versions of SQLite (version 3.3.8 and later) include
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
** and later) include
** support for additional result codes that provide more detailed information
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
@@ -976,6 +978,12 @@ struct sqlite3_io_methods {
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
** underlying native file handle associated with a file handle. This file
** control interprets its argument as a pointer to a native file handle and
** writes the resulting value there.
**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
** opcode causes the xFileControl method to swap the file handle with the one
@@ -1026,6 +1034,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_RBU 26
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
#define SQLITE_FCNTL_PDB 30
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1969,13 +1979,36 @@ struct sqlite3_mem_methods {
** be a NULL pointer, in which case the new setting is not reported back.
** </dd>
**
** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
** <dd> ^This option is used to change the name of the "main" database
** schema. ^The sole argument is a pointer to a constant UTF8 string
** which will become the new schema name in place of "main". ^SQLite
** does not make a copy of the new main schema name string, so the application
** must ensure that the argument passed into this DBCONFIG option is unchanged
** until after the database connection closes.
** </dd>
**
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
** <dd> Usually, when a database in wal mode is closed or detached from a
** database handle, SQLite checks if this will mean that there are now no
** connections at all to the database. If so, it performs a checkpoint
** operation before closing the connection. This option may be used to
** override this behaviour. The first parameter passed to this operation
** is an integer - non-zero to disable checkpoints-on-close, or zero (the
** default) to enable them. The second parameter is a pointer to an integer
** into which is written 0 or 1 to indicate whether checkpoints-on-close
** have been disabled - 0 if they are not disabled, 1 if they are.
** </dd>
**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
/*
@@ -3577,6 +3610,10 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
** sqlite3_stmt_readonly() to return true since, while those statements
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
** sqlite3_stmt_readonly() returns false for those commands.
*/
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
@@ -4041,7 +4078,8 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** other than [SQLITE_ROW] before any subsequent invocation of
** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
** break because any application that ever receives an SQLITE_MISUSE error
@@ -5404,7 +5442,8 @@ SQLITE_API void *sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
@@ -5498,7 +5537,8 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
** the soft heap limit is enforced
** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
** the soft heap limit is enforced on every memory allocation. Without
@@ -5892,13 +5932,15 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for version 3.9.0. It may therefore only be used if
** was added for [version 3.9.0] ([dateof:3.9.0]).
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
@@ -6596,7 +6638,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
@@ -6700,6 +6742,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
@@ -8186,7 +8229,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** See also: [sqlite3_update_hook()]
*/
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
SQLITE_API void *sqlite3_preupdate_hook(
sqlite3 *db,
void(*xPreUpdate)(
void *pCtx, /* Copy of third arg to preupdate_hook() */
@@ -8199,10 +8243,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
),
void*
);
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
#endif
/*
** CAPI3REF: Low-level system error code
@@ -8218,7 +8263,7 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
** KEYWORDS: {snapshot}
** KEYWORDS: {snapshot} {sqlite3_snapshot}
** EXPERIMENTAL
**
** An instance of the snapshot object records the state of a [WAL mode]
@@ -8242,7 +8287,9 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
** to an historical snapshot (if possible). The destructor for
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
typedef struct sqlite3_snapshot sqlite3_snapshot;
typedef struct sqlite3_snapshot {
unsigned char hidden[48];
} sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
@@ -8253,9 +8300,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
** ^If schema S of [database connection] D is not a [WAL mode] database
** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
** leaves the *P value unchanged and returns an appropriate [error code].
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
** The following must be true for this function to succeed. If any of
** the following statements are false when sqlite3_snapshot_get() is
** called, SQLITE_ERROR is returned. The final value of *P is undefined
** in this case.
**
** <ul>
** <li> The database handle must be in [autocommit mode].
**
** <li> Schema S of [database connection] D must be a [WAL mode] database.
**
** <li> There must not be a write transaction open on schema S of database
** connection D.
**
** <li> One or more transactions must have been written to the current wal
** file since it was created on disk (by any connection). This means
** that a snapshot cannot be taken on a wal mode database with no wal
** file immediately after it is first opened. At least one transaction
** must be written to it first.
** </ul>
**
** This function may also return SQLITE_NOMEM. If it is called with the
** database handle in autocommit mode but fails for some other reason,
** whether or not a read transaction is opened on schema S is undefined.
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
@@ -8348,6 +8418,28 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
sqlite3_snapshot *p2
);
/*
** CAPI3REF: Recover snapshots from a wal file
** EXPERIMENTAL
**
** If all connections disconnect from a database file but do not perform
** a checkpoint, the existing wal file is opened along with the database
** file the next time the database is opened. At this point it is only
** possible to successfully call sqlite3_snapshot_open() to open the most
** recent snapshot of the database (the one at the head of the wal file),
** even though the wal file may contain other valid snapshots for which
** clients have sqlite3_snapshot handles.
**
** This function attempts to scan the wal file associated with database zDb
** of database handle db and make all valid snapshots available to
** sqlite3_snapshot_open(). It is an error if there is already a read
** transaction open on the database, or if the database is not a wal mode
** database.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
@@ -8639,7 +8731,7 @@ int sqlite3session_attach(
** CAPI3REF: Set a table filter on a Session Object.
**
** The second argument (xFilter) is the "filter callback". For changes to rows
** in tables that are not attached to the Session oject, the filter is called
** in tables that are not attached to the Session object, the filter is called
** to determine whether changes to the table's rows should be tracked or not.
** If xFilter returns 0, changes is not tracked. Note that once a table is
** attached, xFilter will not be called again.
@@ -8905,7 +8997,7 @@ int sqlite3session_isempty(sqlite3_session *pSession);
** [sqlite3changeset_invert()] functions, all changes within the changeset
** that apply to a single table are grouped together. This means that when
** an application iterates through a changeset using an iterator created by
** this function, all changes that relate to a single table are visted
** this function, all changes that relate to a single table are visited
** consecutively. There is no chance that the iterator will visit a change
** the applies to table X, then one for table Y, and then later on visit
** another change for table X.
@@ -8992,7 +9084,7 @@ int sqlite3changeset_op(
** 0x01 if the corresponding column is part of the tables primary key, or
** 0x00 if it is not.
**
** If argumet pnCol is not NULL, then *pnCol is set to the number of columns
** If argument pnCol is not NULL, then *pnCol is set to the number of columns
** in the table.
**
** If this function is called when the iterator does not point to a valid
@@ -9209,12 +9301,12 @@ int sqlite3changeset_concat(
/*
** Changegroup handle.
** CAPI3REF: Changegroup Handle
*/
typedef struct sqlite3_changegroup sqlite3_changegroup;
/*
** CAPI3REF: Combine two or more changesets into a single changeset.
** CAPI3REF: Create A New Changegroup Object
**
** An sqlite3_changegroup object is used to combine two or more changesets
** (or patchsets) into a single changeset (or patchset). A single changegroup
@@ -9251,6 +9343,8 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add A Changeset To A Changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
** nData bytes) to the changegroup.
**
@@ -9265,7 +9359,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** apply to the same row as a change already present in the changegroup if
** the two rows have the same primary key.
**
** Changes to rows that that do not already appear in the changegroup are
** Changes to rows that do not already appear in the changegroup are
** simply copied into it. Or, if both the new changeset and the changegroup
** contain changes that apply to a single row, the final contents of the
** changegroup depends on the type of each change, as follows:
@@ -9326,6 +9420,8 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
**
** Obtain a buffer containing a changeset (or patchset) representing the
** current contents of the changegroup. If the inputs to the changegroup
** were themselves changesets, the output is a changeset. Or, if the
@@ -9354,7 +9450,7 @@ int sqlite3changegroup_output(
);
/*
** Delete a changegroup object.
** CAPI3REF: Delete A Changegroup Object
*/
void sqlite3changegroup_delete(sqlite3_changegroup*);
+2
Ver Arquivo
@@ -1,6 +1,8 @@
project(cmd)
set(CMAKE_AUTOMOC TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
set(cmd_NAME ${APPLICATION_EXECUTABLE}cmd)
set(cmd_SRC
cmd.cpp
+2 -2
Ver Arquivo
@@ -121,7 +121,7 @@ QString queryPassword(const QString &user)
class HttpCredentialsText : public HttpCredentials {
public:
HttpCredentialsText(const QString& user, const QString& password)
: HttpCredentials(user, password, "", ""), // FIXME: not working with client certs yet (qknight)
: HttpCredentials(user, password), // FIXME: not working with client certs yet (qknight)
_sslTrusted(false)
{}
@@ -507,7 +507,7 @@ restart_sync:
app.exec();
if (engine.isAnotherSyncNeeded()) {
if (engine.isAnotherSyncNeeded() != NoFollowUpSync) {
if (restartCount < options.restartTimes) {
restartCount++;
qDebug() << "Restarting Sync, because another sync is needed" << restartCount;
+2 -1
Ver Arquivo
@@ -3,6 +3,8 @@ set(CMAKE_AUTOMOC TRUE)
add_subdirectory(updater)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
#TODO Move resources files
qt_add_resources(MIRALL_RC_SRC ../../client.qrc)
if ( IS_DIRECTORY ${OEM_THEME_DIR} )
@@ -151,7 +153,6 @@ set(3rdparty_SRC
../3rdparty/qtsingleapplication/qtlocalpeer.cpp
../3rdparty/qtsingleapplication/qtsingleapplication.cpp
../3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp
../3rdparty/certificates/p12topem.cpp
)
if (APPLE)
+15 -1
Ver Arquivo
@@ -214,6 +214,17 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
auto acc = createAccount();
QString authType = settings.value(QLatin1String(authTypeC)).toString();
// There was an account-type saving bug when 'skip folder config' was used
// See #5408. This attempts to fix up the "dummy" authType
if (authType == QLatin1String("dummy")) {
if (settings.contains(QLatin1String("http_user"))) {
authType = "http";
} else if (settings.contains(QLatin1String("shibboleth_shib_user"))) {
authType = "shibboleth";
}
}
QString overrideUrl = Theme::instance()->overrideServerUrl();
QString forceAuth = Theme::instance()->forceConfigAuthType();
if(!forceAuth.isEmpty() && !overrideUrl.isEmpty() ) {
@@ -224,6 +235,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
@@ -237,7 +251,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
acc->setCredentials(CredentialsFactory::create(authType));
// now the cert, it is in the general group
// now the server cert, it is in the general group
settings.beginGroup(QLatin1String("General"));
acc->setApprovedCerts(QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray()));
settings.endGroup();
+6
Ver Arquivo
@@ -214,8 +214,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
}
tv->setCurrentIndex(index);
QString alias = _model->data( index, FolderStatusDelegate::FolderAliasRole ).toString();
bool folderPaused = _model->data( index, FolderStatusDelegate::FolderSyncPaused).toBool();
bool folderConnected = _model->data( index, FolderStatusDelegate::FolderAccountConnected ).toBool();
auto folderMan = FolderMan::instance();
QMenu *menu = new QMenu(tv);
menu->setAttribute(Qt::WA_DeleteOnClose);
@@ -231,6 +233,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
if (!folderPaused) {
ac = menu->addAction(tr("Force sync now"));
if (folderMan->currentSyncFolder() == folderMan->folder(alias)) {
ac->setText(tr("Restart sync"));
}
ac->setEnabled(folderConnected);
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotForceSyncCurrentFolder()));
}
+2 -2
Ver Arquivo
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>462</width>
<height>186</height>
<height>188</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,7 +32,7 @@
<item row="0" column="0">
<widget class="QLabel" name="labelCertificateFile">
<property name="text">
<string>Certificate :</string>
<string>Certificate &amp; Key (pkcs12) :</string>
</property>
</widget>
</item>
-12
Ver Arquivo
@@ -347,14 +347,6 @@ void Application::slotownCloudWizardDone( int res )
}
}
static void csyncLogCatcher(int /*verbosity*/,
const char */*function*/,
const char *buffer,
void */*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
void Application::setupLogging()
{
// might be called from second instance
@@ -370,10 +362,6 @@ void Application::setupLogging()
.arg(property("ui_lang").toString())
.arg(_theme->version())
.arg(Utility::platformName());
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 );
}
void Application::slotUseMonoIconsChanged(bool)
+1 -1
Ver Arquivo
@@ -27,7 +27,7 @@ class HttpCredentialsGui : public HttpCredentials {
Q_OBJECT
public:
explicit HttpCredentialsGui() : HttpCredentials() {}
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
HttpCredentialsGui(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key) : HttpCredentials(user, password, certificate, key) {}
void askFromUser() Q_DECL_OVERRIDE;
Q_INVOKABLE void askFromUserAsync();
+3 -8
Ver Arquivo
@@ -46,8 +46,6 @@
namespace OCC {
const char oldJournalPath[] = ".csync_journal.db";
Folder::Folder(const FolderDefinition& definition,
AccountState* accountState,
QObject* parent)
@@ -65,9 +63,6 @@ Folder::Folder(const FolderDefinition& definition,
, _fileLog(new SyncRunFileLog)
, _saveBackwardsCompatible(false)
{
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
qsrand(QTime::currentTime().msec());
_timeSinceLastSyncStart.start();
_timeSinceLastSyncDone.start();
@@ -826,7 +821,7 @@ void Folder::slotSyncFinished(bool success)
_fileLog->finish();
bubbleUpSyncResult();
bool anotherSyncNeeded = _engine->isAnotherSyncNeeded();
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
@@ -877,7 +872,7 @@ void Folder::slotSyncFinished(bool success)
_timeSinceLastSyncDone.restart();
// Increment the follow-up sync counter if necessary.
if (anotherSyncNeeded) {
if (anotherSyncNeeded == ImmediateFollowUp) {
_consecutiveFollowUpSyncs++;
qDebug() << "another sync was requested by the finished sync, this has"
<< "happened" << _consecutiveFollowUpSyncs << "times";
@@ -886,7 +881,7 @@ void Folder::slotSyncFinished(bool success)
}
// Maybe force a follow-up sync to take place, but only a couple of times.
if (anotherSyncNeeded && _consecutiveFollowUpSyncs <= 3)
if (anotherSyncNeeded == ImmediateFollowUp && _consecutiveFollowUpSyncs <= 3)
{
// Sometimes another sync is requested because a local file is still
// changing, so wait at least a small amount of time before syncing
+19 -12
Ver Arquivo
@@ -115,7 +115,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)));
}
@@ -148,6 +148,7 @@ int FolderMan::unloadAndDeleteAllFolders()
void FolderMan::registerFolderMonitor( Folder *folder )
{
if( !folder ) return;
if( !QDir(folder->path()).exists() ) return;
if( !_folderWatchers.contains(folder->alias() ) ) {
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
@@ -730,6 +731,10 @@ void FolderMan::slotStartScheduledFolderSync()
// Start syncing this folder!
if( folder ) {
// Safe to call several times, and necessary to try again if
// the folder path didn't exist previously.
registerFolderMonitor(folder);
_currentSyncFolder = folder;
folder->startSync( QStringList() );
}
@@ -833,18 +838,20 @@ void FolderMan::slotScheduleFolderByTime()
continue;
}
// Retry a couple of times after failure
bool syncAgainAfterFail = f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3;
qint64 syncAgainAfterFailDelay = 10 * 1000; // 10s for the first retry-after-fail
// Retry a couple of times after failure; or regularly if requested
bool syncAgain =
(f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3)
|| f->syncEngine().isAnotherSyncNeeded() == DelayedFollowUp;
qint64 syncAgainDelay = 10 * 1000; // 10s for the first retry-after-fail
if (f->consecutiveFailingSyncs() > 1)
syncAgainAfterFailDelay = 60 * 1000; // 60s for each further attempt
if (syncAgainAfterFail
&& msecsSinceSync > syncAgainAfterFailDelay) {
syncAgainDelay = 60 * 1000; // 60s for each further attempt
if (syncAgain
&& msecsSinceSync > syncAgainDelay) {
qDebug() << "** scheduling folder" << f->alias()
<< "because the last"
<< f->consecutiveFailingSyncs() << "syncs failed, last status:"
<< f->syncResult().statusString()
<< "time since last sync:" << msecsSinceSync;
<< ", the last" << f->consecutiveFailingSyncs() << "syncs failed"
<< ", anotherSyncNeeded" << f->syncEngine().isAnotherSyncNeeded()
<< ", last status:" << f->syncResult().statusString()
<< ", time since last sync:" << msecsSinceSync;
scheduleFolder(f);
continue;
@@ -931,7 +938,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)));
+6 -9
Ver Arquivo
@@ -527,10 +527,8 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
if (!info || info->_fetched || info->_fetching)
return;
info->_hasError = false;
info->resetSubs(this, parent);
info->_fetching = true;
info->_fetchingLabel = false;
QString path = info->_folder->remotePath();
if (info->_path != QLatin1String("/")) {
if (!path.endsWith(QLatin1Char('/'))) {
@@ -698,17 +696,16 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
qDebug() << r->errorString();
parentInfo->_lastErrorString = r->errorString();
parentInfo->resetSubs(this, idx);
if (r->error() == QNetworkReply::ContentNotFoundError) {
parentInfo->_fetched = true;
} else {
if (!parentInfo->hasLabel()) {
beginInsertRows(idx, 0, 0);
endInsertRows();
}
Q_ASSERT(!parentInfo->hasLabel());
beginInsertRows(idx, 0, 0);
parentInfo->_hasError = true;
endInsertRows();
}
parentInfo->_fetching = false;
parentInfo->_fetchingLabel = false;
}
}
+2 -1
Ver Arquivo
@@ -110,7 +110,8 @@ void GeneralSettings::loadMiscSettings()
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
}
+2 -1
Ver Arquivo
@@ -110,8 +110,9 @@ LogBrowser::LogBrowser(QWidget *parent) :
setModal(false);
Logger::instance()->setLogWindowActivated(true);
// Direct connection for log coming from this thread, and queued for the one in a different thread
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
connect(Logger::instance(), SIGNAL(logWindowLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
QAction *showLogWindow = new QAction(this);
showLogWindow->setShortcut(QKeySequence("F12"));
+2 -1
Ver Arquivo
@@ -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;
}
+13 -1
Ver Arquivo
@@ -207,10 +207,15 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
// Do this early because reply might be deleted in message box event loop
QString msg = tr("Failed to connect to %1 at %2:<br/>%3")
QString msg;
if (!_ocWizard->account()->url().isValid()) {
msg = tr("Invalid URL");
} else {
msg = tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString());
}
bool isDowngradeAdvised = checkDowngradeAdvised(reply);
// If a client cert is needed, nginx sends:
@@ -553,6 +558,13 @@ void OwncloudSetupWizard::slotSkipFolderConfiguration()
AccountState *OwncloudSetupWizard::applyAccountChanges()
{
AccountPtr newAccount = _ocWizard->account();
// Detach the account that is going to be saved from the
// wizard to ensure it doesn't accidentally get modified
// later (such as from running cleanup such as
// AbstractCredentialsWizardPage::cleanupPage())
_ocWizard->setAccount(AccountManager::createAccount());
auto manager = AccountManager::instance();
auto newState = manager->addAccount(newAccount);
+61 -6
Ver Arquivo
@@ -40,6 +40,8 @@
#include <QPixmap>
#include <QImage>
#include <QWidgetAction>
#include <QPainter>
#include <QPainterPath>
namespace {
const char TOOLBAR_CSS[] =
@@ -54,6 +56,23 @@ namespace {
namespace OCC {
static QIcon circleMask( const QPixmap& avatar )
{
int dim = avatar.width();
QPixmap fixedImage(dim, dim);
fixedImage.fill(Qt::transparent);
QPainter imgPainter(&fixedImage);
QPainterPath clip;
clip.addEllipse(0, 0, dim, dim);
imgPainter.setClipPath(clip);
imgPainter.drawPixmap(0, 0, dim, dim, avatar);
imgPainter.end();
return QIcon(fixedImage);
}
//
// Whenever you change something here check both settingsdialog.cpp and settingsdialogmac.cpp !
//
@@ -196,8 +215,17 @@ void SettingsDialog::accountAdded(AccountState *s)
bool brandingSingleAccount = !Theme::instance()->multiAccount();
auto accountAction = createColorAwareAction(QLatin1String(":/client/resources/account.png"),
brandingSingleAccount ? tr("Account") : s->account()->displayName());
QAction *accountAction;
QPixmap avatar = s->account()->avatar();
const QString actionText = brandingSingleAccount ? tr("Account") : s->account()->displayName();
if(avatar.isNull()) {
accountAction = createColorAwareAction(QLatin1String(":/client/resources/account.png"),
actionText);
} else {
QIcon icon = circleMask(avatar);
accountAction = createActionWithIcon(icon, actionText);
}
if (!brandingSingleAccount) {
accountAction->setToolTip(s->account()->displayName());
accountAction->setIconText(s->shortDisplayNameForSettings(height * buttonSizeRatio));
@@ -207,14 +235,30 @@ void SettingsDialog::accountAdded(AccountState *s)
_ui->stack->insertWidget(0 , accountSettings);
_actionGroup->addAction(accountAction);
_actionGroupWidgets.insert(accountAction, accountSettings);
_actionForAccount.insert(s->account().data(), accountAction);
connect( accountSettings, SIGNAL(folderChanged()), _gui, SLOT(slotFoldersChanged()));
connect( accountSettings, SIGNAL(openFolderAlias(const QString&)),
_gui, SLOT(slotFolderOpenAction(QString)));
connect(s->account().data(), SIGNAL(accountChangedAvatar()), SLOT(slotAccountAvatarChanged()));
slotRefreshActivity(s);
}
void SettingsDialog::slotAccountAvatarChanged()
{
Account *account = static_cast<Account*>(sender());
if( account && _actionForAccount.contains(account)) {
QAction *action = _actionForAccount[account];
if( action ) {
QPixmap pix = account->avatar();
if( !pix.isNull() ) {
action->setIcon( circleMask(pix) );
}
}
}
}
void SettingsDialog::accountRemoved(AccountState *s)
{
for (auto it = _actionGroupWidgets.begin(); it != _actionGroupWidgets.end(); ++it) {
@@ -236,6 +280,9 @@ void SettingsDialog::accountRemoved(AccountState *s)
}
}
if( _actionForAccount.contains(s->account().data()) ) {
_actionForAccount.remove(s->account().data());
}
_activitySettings->slotRemoveAccount(s);
// Hide when the last account is deleted. We want to enter the same
@@ -306,14 +353,22 @@ public:
}
};
QAction *SettingsDialog::createActionWithIcon(const QIcon& icon, const QString& text, const QString& iconPath)
{
QAction *action = new ToolButtonAction(icon, text, this);
action->setCheckable(true);
if(!iconPath.isEmpty()) {
action->setProperty("iconPath", iconPath);
}
return action;
}
QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const QString &text)
{
// all buttons must have the same size in order to keep a good layout
QIcon coloredIcon = createColorAwareIcon(iconPath);
QAction *action = new ToolButtonAction(coloredIcon, text, this);
action->setCheckable(true);
action->setProperty("iconPath", iconPath);
return action;
return createActionWithIcon(coloredIcon, text, iconPath);
}
void SettingsDialog::slotRefreshActivity( AccountState* accountState )
+7
Ver Arquivo
@@ -58,6 +58,7 @@ public slots:
void showActivityPage();
void slotSwitchPage(QAction *action);
void slotRefreshActivity(AccountState *accountState );
void slotAccountAvatarChanged();
protected:
void reject() Q_DECL_OVERRIDE;
@@ -73,12 +74,18 @@ private:
QIcon createColorAwareIcon(const QString &name);
QAction *createColorAwareAction(const QString &iconName, const QString &fileName);
QAction *createActionWithIcon(const QIcon& icon, const QString& text, const QString& iconPath = QString());
Ui::SettingsDialog * const _ui;
QActionGroup* _actionGroup;
// Maps the actions from the action group to the corresponding widgets
QHash<QAction*, QWidget*> _actionGroupWidgets;
// Maps the action in the dialog to their according account. Needed in
// case the account avatar changes
QHash<Account*, QAction*> _actionForAccount;
QToolBar* _toolBar;
ActivitySettings *_activitySettings;
+1 -1
Ver Arquivo
@@ -229,7 +229,7 @@ void ShareLinkWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shar
Q_FOREACH(auto share, shares) {
if (share->getShareType() == Share::TypeLink) {
_share = qSharedPointerDynamicCast<LinkShare>(share);
_share = qSharedPointerObjectCast<LinkShare>(share);
_ui->pushButton_copy->show();
_ui->pushButton_mail->show();
+153 -100
Ver Arquivo
@@ -32,8 +32,10 @@
#include "account.h"
#include "capabilities.h"
#include <QBitArray>
#include <QDebug>
#include <QUrl>
#include <QMetaMethod>
#include <QMetaObject>
#include <QStringList>
#include <QScopedPointer>
@@ -56,6 +58,11 @@
// The second number should be changed when there are new features.
#define MIRALL_SOCKET_API_VERSION "1.0"
#define DEBUG qDebug() << "SocketApi: "
Q_DECLARE_METATYPE(OCC::SocketListener)
static inline QString removeTrailingSlash(QString path)
{
Q_ASSERT(path.endsWith(QLatin1Char('/')));
@@ -63,9 +70,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 = nullptr) : 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 +216,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);
Q_ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
_listeners.clear();
}
@@ -143,14 +230,16 @@ void SocketApi::slotNewConnection()
DEBUG << "New connection" << socket;
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
Q_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 +247,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);
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 +289,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 +304,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 +325,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 +370,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 +399,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 +417,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 +426,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 +440,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 +467,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 +475,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 +494,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
Ver Arquivo
@@ -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;
};
+13 -10
Ver Arquivo
@@ -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
+4 -4
Ver Arquivo
@@ -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;
+4
Ver Arquivo
@@ -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"));
+3 -1
Ver Arquivo
@@ -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();
@@ -29,8 +29,11 @@ OwncloudConnectionMethodDialog::OwncloudConnectionMethodDialog(QWidget *parent)
connect(ui->btnClientSideTLS, SIGNAL(clicked(bool)), this, SLOT(returnClientSideTLS()));
connect(ui->btnBack, SIGNAL(clicked(bool)), this, SLOT(returnBack()));
// DM: TLS Client Cert GUI support disabled for now
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
// We support only from Qt 5.4.x because of https://doc.qt.io/qt-5/qsslcertificate.html#importPkcs12
ui->btnClientSideTLS->hide();
#endif
}
void OwncloudConnectionMethodDialog::setUrl(const QUrl &url)
+1 -1
Ver Arquivo
@@ -192,7 +192,7 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const
{
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->ownCloudCertificatePath, _ocWizard->ownCloudCertificatePasswd);
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->_clientSslCertificate, _ocWizard->_clientSslKey);
}
+31 -31
Ver Arquivo
@@ -21,13 +21,13 @@
#include <QMessageBox>
#include <QSsl>
#include <QSslCertificate>
#include <QNetworkAccessManager>
#include "QProgressIndicator.h"
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudsetuppage.h"
#include "wizard/owncloudconnectionmethoddialog.h"
#include "../3rdparty/certificates/p12topem.h"
#include "theme.h"
#include "account.h"
@@ -71,7 +71,6 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
addCertDial = new AddCertificateDialog(this);
connect(_ocWizard,SIGNAL(needCertificate()),this,SLOT(slotAskSSLClientCertificate()));
}
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
@@ -139,7 +138,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
void OwncloudSetupPage::slotUrlEditFinished()
{
QString url = _ui.leUrl->fullText();
if (QUrl(url).isRelative()) {
if (QUrl(url).isRelative() && !url.isEmpty()) {
// no scheme defined, set one
url.prepend("https://");
}
@@ -269,7 +268,10 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
}
break;
case OwncloudConnectionMethodDialog::Client_Side_TLS:
slotAskSSLClientCertificate();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
#endif
break;
case OwncloudConnectionMethodDialog::Closed:
case OwncloudConnectionMethodDialog::Back:
@@ -302,12 +304,6 @@ void OwncloudSetupPage::stopSpinner()
_progressIndi->stopAnimation();
}
void OwncloudSetupPage::slotAskSSLClientCertificate()
{
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
}
QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
@@ -320,36 +316,40 @@ QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
//called during the validation of the client certificate.
void OwncloudSetupPage::slotCertificateAccepted()
{
QSslCertificate sslCertificate;
resultP12ToPem certif = p12ToPem(addCertDial->getCertificatePath().toStdString() , addCertDial->getCertificatePasswd().toStdString());
if(certif.ReturnCode){
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(ba, QSsl::Pem);
sslCertificate = sslCertificateList.takeAt(0);
_ocWizard->ownCloudCertificate = ba;
_ocWizard->ownCloudPrivateKey = certif.PrivateKey.c_str();
_ocWizard->ownCloudCertificatePath = addCertDial->getCertificatePath();
_ocWizard->ownCloudCertificatePasswd = addCertDial->getCertificatePasswd();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
QList<QSslCertificate> clientCaCertificates;
QFile certFile(addCertDial->getCertificatePath());
certFile.open(QFile::ReadOnly);
if(QSslCertificate::importPkcs12(&certFile,
&_ocWizard->_clientSslKey, &_ocWizard->_clientSslCertificate,
&clientCaCertificates,
addCertDial->getCertificatePasswd().toLocal8Bit())){
AccountPtr acc = _ocWizard->account();
acc->setCertificate(_ocWizard->ownCloudCertificate, _ocWizard->ownCloudPrivateKey);
addCertDial->reinit();
// to re-create the session ticket because we added a key/cert
acc->setSslConfiguration(QSslConfiguration());
QSslConfiguration sslConfiguration = acc->getOrCreateSslConfig();
// We're stuffing the certificate into the configuration form here. Later the
// cert will come via the HttpCredentials
sslConfiguration.setLocalCertificate(_ocWizard->_clientSslCertificate);
sslConfiguration.setPrivateKey(_ocWizard->_clientSslKey);
acc->setSslConfiguration(sslConfiguration);
// Make sure TCP connections get re-established
acc->networkAccessManager()->clearAccessCache();
addCertDial->reinit(); // FIXME: Why not just have this only created on use?
validatePage();
} else {
QString message;
message = certif.Comment.c_str();
addCertDial->showErrorMessage(message);
addCertDial->showErrorMessage("Could not load certificate");
addCertDial->show();
}
#endif
}
OwncloudSetupPage::~OwncloudSetupPage()
{
delete addCertDial;
}
} // namespace OCC
-1
Ver Arquivo
@@ -59,7 +59,6 @@ public slots:
void setErrorString( const QString&, bool retryHTTPonly );
void startSpinner();
void stopSpinner();
void slotAskSSLClientCertificate();
void slotCertificateAccepted();
protected slots:
-7
Ver Arquivo
@@ -224,11 +224,4 @@ AbstractCredentials* OwncloudWizard::getCredentials() const
return 0;
}
// outputs the signal needed to authenticate a certificate
void OwncloudWizard::raiseCertificatePopup()
{
emit needCertificate();
}
} // end namespace
+6 -5
Ver Arquivo
@@ -17,6 +17,8 @@
#define MIRALL_OWNCLOUD_WIZARD_H
#include <QWizard>
#include <QSslKey>
#include <QSslCertificate>
#include "wizard/owncloudwizardcommon.h"
#include "accountfwd.h"
@@ -63,11 +65,10 @@ public:
void displayError( const QString&, bool retryHTTPonly);
AbstractCredentials* getCredentials() const;
void raiseCertificatePopup();
QByteArray ownCloudCertificate;
QString ownCloudPrivateKey;
QString ownCloudCertificatePath;
QString ownCloudCertificatePasswd;
// FIXME: Can those be local variables?
// Set from the OwncloudSetupPage, later used from OwncloudHttpCredsPage
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
public slots:
void setAuthType(WizardCommon::AuthType type);
+2 -1
Ver Arquivo
@@ -1,6 +1,8 @@
project(libsync)
set(CMAKE_AUTOMOC TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
configure_file( version.h.in "${CMAKE_CURRENT_BINARY_DIR}/version.h" )
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
@@ -70,7 +72,6 @@ set(libsync_SRCS
creds/abstractcredentials.cpp
creds/credentialscommon.cpp
../3rdparty/qjson/json.cpp
../3rdparty/certificates/p12topem.cpp
)
if(TOKEN_AUTH_ONLY)
+21 -33
Ver Arquivo
@@ -18,7 +18,6 @@
#include "configfile.h"
#include "accessmanager.h"
#include "creds/abstractcredentials.h"
#include "../3rdparty/certificates/p12topem.h"
#include "capabilities.h"
#include "theme.h"
@@ -91,9 +90,19 @@ void Account::setDavUser(const QString &newDavUser)
_davUser = newDavUser;
}
QPixmap Account::avatar() const
{
return _avatarPixmap;
}
void Account::setAvatar(const QPixmap& pixmap)
{
_avatarPixmap = pixmap;
emit accountChangedAvatar();
}
QString Account::displayName() const
{
QString dn = QString("%1@%2").arg(davUser(), _url.host());
QString dn = QString("%1@%2").arg(_credentials->user(), _url.host());
int port = url().port();
if (port > 0 && port != 80 && port != 443) {
dn.append(QLatin1Char(':'));
@@ -149,10 +158,14 @@ QUrl Account::davUrl() const
return Utility::concatUrlPath(url(), davPath());
}
/**
* clear all cookies. (Session cookies or not)
*/
void Account::clearCookieJar()
{
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
static_cast<CookieJar*>(_am->cookieJar())->clearSessionCookies();
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
emit wantsAccountSaved(this);
}
/*! This shares our official cookie jar (containing all the tasty
@@ -242,12 +255,6 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNet
return _am->sendCustomRequest(req, verb, data);
}
void Account::setCertificate(const QByteArray certficate, const QString privateKey)
{
_pemCertificate=certficate;
_pemPrivateKey=privateKey;
}
void Account::setSslConfiguration(const QSslConfiguration &config)
{
_sslConfiguration = config;
@@ -264,31 +271,7 @@ QSslConfiguration Account::getOrCreateSslConfig()
// if setting the client certificate fails, you will probably get an error similar to this:
// "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
QSslCertificate sslClientCertificate;
ConfigFile cfgFile;
if(!cfgFile.certificatePath().isEmpty() && !cfgFile.certificatePasswd().isEmpty()) {
resultP12ToPem certif = p12ToPem(cfgFile.certificatePath().toStdString(), cfgFile.certificatePasswd().toStdString());
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
this->setCertificate(ba, QString::fromStdString(certif.PrivateKey));
}
if((!_pemCertificate.isEmpty())&&(!_pemPrivateKey.isEmpty())) {
// Read certificates
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(_pemCertificate, QSsl::Pem);
if(sslCertificateList.length() != 0) {
sslClientCertificate = sslCertificateList.takeAt(0);
}
// Read key from file
QSslKey privateKey(_pemPrivateKey.toLocal8Bit(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey , "");
// SSL configuration
sslConfig.setCaCertificates(QSslSocket::systemCaCertificates());
sslConfig.setLocalCertificate(sslClientCertificate);
sslConfig.setPrivateKey(privateKey);
qDebug() << "Added SSL client certificate to the query";
}
#if QT_VERSION > QT_VERSION_CHECK(5, 2, 0)
// Try hard to re-use session for different requests
sslConfig.setSslOption(QSsl::SslOptionDisableSessionTickets, false);
@@ -379,8 +362,11 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// Keep a ref here on our stackframe to make sure that it doesn't get deleted before
// handleErrors returns.
QSharedPointer<QNetworkAccessManager> qnamLock = _am;
QPointer<QObject> guard = reply;
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
if (!guard) return;
QSslSocket::addDefaultCaCertificates(approvedCerts);
addApprovedCerts(approvedCerts);
emit wantsAccountSaved(this);
@@ -392,6 +378,8 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// certificate changes.
reply->ignoreSslErrors(errors);
} else {
if (!guard) return;
// Mark all involved certificates as rejected, so we don't ask the user again.
foreach (const QSslError &error, errors) {
if (!_rejectedCertificates.contains(error.certificate())) {
+9 -2
Ver Arquivo
@@ -26,6 +26,8 @@
#include <QSslCipher>
#include <QSslError>
#include <QSharedPointer>
#include <QPixmap>
#include "utility.h"
#include <memory>
#include "capabilities.h"
@@ -78,6 +80,9 @@ public:
QString davUser() const;
void setDavUser(const QString &newDavUser);
QPixmap avatar() const;
void setAvatar(const QPixmap& pixmap);
/// The name of the account as shown in the toolbar
QString displayName() const;
@@ -197,6 +202,8 @@ signals:
void serverVersionChanged(Account* account, const QString& newVersion, const QString& oldVersion);
void accountChangedAvatar();
protected Q_SLOTS:
void slotHandleSslErrors(QNetworkReply*,QList<QSslError>);
void slotCredentialsFetched();
@@ -209,6 +216,7 @@ private:
QWeakPointer<Account> _sharedThis;
QString _id;
QString _davUser;
QPixmap _avatarPixmap;
QMap<QString, QVariant> _settingsMap;
QUrl _url;
QList<QSslCertificate> _approvedCerts;
@@ -224,8 +232,7 @@ private:
QList<QSslCertificate> _rejectedCertificates;
static QString _configFileName;
QByteArray _pemCertificate;
QString _pemPrivateKey;
QString _davPath; // defaults to value from theme, might be overwritten in brandings
friend class AccountManager;
};
+11 -5
Ver Arquivo
@@ -116,12 +116,18 @@ bool Capabilities::chunkingNg() const
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
}
quint64 Capabilities::requestMaxDurationDC() const
bool Capabilities::chunkingParallelUploadDisabled() const
{
QByteArray requestMaxDurationDC = _capabilities["dav"].toMap()["max_single_upload_request_duration_msec"].toByteArray();
if (!requestMaxDurationDC.isEmpty())
return requestMaxDurationDC.toLongLong();
return 0;
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;
}
}
+22 -1
Ver Arquivo
@@ -41,7 +41,9 @@ public:
int sharePublicLinkExpireDateDays() const;
bool shareResharing() const;
bool chunkingNg() const;
quint64 requestMaxDurationDC() const;
/// disable parallel upload in chunking
bool chunkingParallelUploadDisabled() const;
/// returns true if the capabilities report notifications
bool notificationsAvailable() const;
@@ -79,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;
};
-13
Ver Arquivo
@@ -52,7 +52,6 @@ static const char updateCheckIntervalC[] = "updateCheckInterval";
static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout";
static const char chunkSizeC[] = "chunkSize";
static const char maxChunkSizeC[] = "maxChunkSizeC";
static const char proxyHostC[] = "Proxy/host";
static const char proxyTypeC[] = "Proxy/type";
@@ -129,18 +128,6 @@ quint64 ConfigFile::chunkSize() const
return settings.value(QLatin1String(chunkSizeC), 10*1000*1000).toLongLong(); // default to 10 MB
}
quint64 ConfigFile::maxChunkSize() const
{
QSettings settings(configFile(), QSettings::IniFormat);
return settings.value(QLatin1String(maxChunkSizeC), 50*1000*1000).toLongLong(); // default to 50 MB
}
quint64 ConfigFile::minChunkSize() const
{
QSettings settings(configFile(), QSettings::IniFormat);
return settings.value(QLatin1String(maxChunkSizeC), 1000*1000).toLongLong(); // default to 1 MB
}
void ConfigFile::setOptionalDesktopNotifications(bool show)
{
QSettings settings(configFile(), QSettings::IniFormat);
-2
Ver Arquivo
@@ -113,8 +113,6 @@ public:
int timeout() const;
quint64 chunkSize() const;
quint64 maxChunkSize() const;
quint64 minChunkSize() const;
void saveGeometry(QWidget *w);
void restoreGeometry(QWidget *w);
+18 -1
Ver Arquivo
@@ -15,6 +15,7 @@
#include <QtCore>
#include <QNetworkReply>
#include <QNetworkProxyFactory>
#include <QPixmap>
#include "connectionvalidator.h"
#include "account.h"
@@ -144,7 +145,12 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
// status.php could not be loaded (network or server issue!).
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString() << reply->peek(1024);
if (reply && !_account->credentials()->ready()) {
// This could be needed for SSL client certificates
// We need to load them from keychain and try
reportResult( CredentialsMissingOrWrong );
} else
if( reply && ! _account->credentials()->stillValid(reply)) {
_errors.append(tr("Authentication error: Either username or password are wrong."));
} else {
@@ -247,7 +253,18 @@ void ConnectionValidator::slotUserFetched(const QVariantMap &json)
QString user = json.value("ocs").toMap().value("data").toMap().value("id").toString();
if (!user.isEmpty()) {
_account->setDavUser(user);
AvatarJob *job = new AvatarJob(_account, this);
job->setTimeout(20*1000);
QObject::connect(job, SIGNAL(avatarPixmap(QPixmap)), this, SLOT(slotAvatarPixmap(QPixmap)));
job->start();
}
}
void ConnectionValidator::slotAvatarPixmap(const QPixmap& pixmap)
{
_account->setAvatar(pixmap);
reportResult(Connected);
}
+5 -1
Ver Arquivo
@@ -68,7 +68,10 @@ namespace OCC {
+-> fetchUser
PropfindJob
|
+-> slotUserFetched --> X
+-> slotUserFetched
AvatarJob
|
+-> slotAvatarPixmap --> reportResult()
\endcode
*/
@@ -119,6 +122,7 @@ protected slots:
void slotCapabilitiesRecieved(const QVariantMap&);
void slotUserFetched(const QVariantMap &);
void slotAvatarPixmap(const QPixmap&);
private:
void reportResult(Status status);
+129 -47
Ver Arquivo
@@ -17,6 +17,7 @@
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QSslKey>
#include <keychain.h>
@@ -36,8 +37,8 @@ namespace OCC
namespace
{
const char userC[] = "user";
const char certifPathC[] = "certificatePath";
const char certifPasswdC[] = "certificatePasswd";
const char clientCertificatePEMC[] = "_clientCertificatePEM";
const char clientKeyPEMC[] = "_clientKeyPEM";
const char authenticationFailedC[] = "owncloud-authentication-failed";
} // ns
@@ -50,24 +51,47 @@ protected:
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
//qDebug() << "Request for " << req.url() << "with authorization"
// << QByteArray::fromBase64(credHash)
// << _cred->_clientSslKey << _cred->_clientSslCertificate
// << _cred->_clientSslKey.isNull() << _cred->_clientSslCertificate.isNull();
if (!_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) {
// SSL configuration
QSslConfiguration sslConfiguration = req.sslConfiguration();
sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
sslConfiguration.setPrivateKey(_cred->_clientSslKey);
req.setSslConfiguration(sslConfiguration);
}
return AccessManager::createRequest(op, req, outgoingData);
}
private:
const HttpCredentials *_cred;
};
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account);
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
HttpCredentials::HttpCredentials()
: _ready(false)
{
}
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd)
// From wizard
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key)
: _user(user),
_password(password),
_ready(true),
_certificatePath(certificatePath),
_certificatePasswd(certificatePasswd)
_clientSslKey(key),
_clientSslCertificate(certificate)
{
}
@@ -86,16 +110,6 @@ QString HttpCredentials::password() const
return _password;
}
QString HttpCredentials::certificatePath() const
{
return _certificatePath;
}
QString HttpCredentials::certificatePasswd() const
{
return _certificatePasswd;
}
void HttpCredentials::setAccount(Account* account)
{
AbstractCredentials::setAccount(account);
@@ -129,35 +143,83 @@ void HttpCredentials::fetchFromKeychain()
{
// User must be fetched from config file
fetchUser();
_certificatePath = _account->credentialSetting(QLatin1String(certifPathC)).toString();
_certificatePasswd = _account->credentialSetting(QLatin1String(certifPasswdC)).toString();
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
const QString kck = keychainKey(_account->url().toString(), _user );
QString key = QString::fromLatin1( "%1/data" ).arg( kck );
if( settings && settings->contains(key) ) {
// Clean the password from the config file if it is in there.
// we do not want a security problem.
settings->remove(key);
key = QString::fromLatin1( "%1/type" ).arg( kck );
settings->remove(key);
settings->sync();
}
if (_ready) {
Q_EMIT fetched();
} else {
// Read client cert from keychain
const QString kck = keychainKey(_account->url().toString(), _user + clientCertificatePEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
qDebug() << "-------- ----->" << _clientSslCertificate << _clientSslKey;
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientCertPEMJobDone(QKeychain::Job*)));
job->start();
}
}
void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job* incoming)
{
// Store PEM in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
if(sslCertificateList.length() >= 1) {
_clientSslCertificate = sslCertificateList.at(0);
}
}
// Load key too
const QString kck = keychainKey(_account->url().toString(), _user + clientKeyPEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientKeyPEMJobDone(QKeychain::Job*)));
job->start();
}
void HttpCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job* incoming)
{
// Store key in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QByteArray clientKeyPEM = readJob->binaryData();
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
// load whatever we have. So we try until it works.
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
// ec keys are Qt 5.5
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
}
#endif
if (_clientSslKey.isNull()) {
qDebug() << "Warning: Could not load SSL key into Qt!";
}
}
// Now fetch the actual server password
const QString kck = keychainKey(_account->url().toString(), _user );
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start();
}
bool HttpCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
@@ -166,10 +228,10 @@ bool HttpCredentials::stillValid(QNetworkReply *reply)
|| !reply->property(authenticationFailedC).toBool()));
}
void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob)
{
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
_password = readJob->textData();
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob*>(incomingJob);
_password = job->textData();
if( _user.isEmpty()) {
qDebug() << "Strange: User is empty!";
@@ -178,7 +240,6 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
QKeychain::Error error = job->error();
if( !_password.isEmpty() && error == NoError ) {
// All cool, the keychain did not come back with error.
// Still, the password can be empty which indicates a problem and
// the password dialog has to be opened.
@@ -214,9 +275,7 @@ void HttpCredentials::invalidateToken()
}
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(true);
job->setKey(kck);
job->start();
@@ -261,14 +320,37 @@ void HttpCredentials::persist()
// We never connected or fetched the user, there is nothing to save.
return;
}
_account->setCredentialSetting(QLatin1String(userC), _user);
_account->setCredentialSetting(QLatin1String(certifPathC), _certificatePath);
_account->setCredentialSetting(QLatin1String(certifPasswdC), _certificatePasswd);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
_account->setCredentialSetting(QLatin1String(userC), _user);
// write cert
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientCertPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC));
job->setBinaryData(_clientSslCertificate.toPem());
job->start();
}
void HttpCredentials::slotWriteClientCertPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
// write ssl key
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientKeyPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC));
job->setBinaryData(_clientSslKey.toPem());
job->start();
}
void HttpCredentials::slotWriteClientKeyPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user));
+15 -9
Ver Arquivo
@@ -17,7 +17,8 @@
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
#include <QMap>
#include <QSslCertificate>
#include <QSslKey>
#include "creds/abstractcredentials.h"
class QNetworkReply;
@@ -25,6 +26,8 @@ class QAuthenticator;
namespace QKeychain {
class Job;
class WritePasswordJob;
class ReadPasswordJob;
}
namespace OCC
@@ -33,10 +36,10 @@ namespace OCC
class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
{
Q_OBJECT
friend class HttpCredentialsAccessManager;
public:
explicit HttpCredentials();
HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd);
HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate = QSslCertificate(), const QSslKey& key = QSslKey());
QString authType() const Q_DECL_OVERRIDE;
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
@@ -50,15 +53,19 @@ public:
void forgetSensitiveData() Q_DECL_OVERRIDE;
QString fetchUser();
virtual bool sslIsTrusted() { return false; }
QString certificatePath() const;
QString certificatePasswd() const;
// To fetch the user name as early as possible
void setAccount(Account* account) Q_DECL_OVERRIDE;
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
void slotReadClientCertPEMJobDone(QKeychain::Job*);
void slotReadClientKeyPEMJobDone(QKeychain::Job*);
void slotReadJobDone(QKeychain::Job*);
void slotWriteClientCertPEMJobDone(QKeychain::Job*);
void slotWriteClientKeyPEMJobDone(QKeychain::Job*);
void slotWriteJobDone(QKeychain::Job*);
void clearQNAMCache();
@@ -66,12 +73,11 @@ protected:
QString _user;
QString _password;
QString _previousPassword;
QString _fetchErrorString;
bool _ready;
private:
QString _certificatePath;
QString _certificatePasswd;
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
};
} // namespace OCC
+28 -7
Ver Arquivo
@@ -19,6 +19,8 @@
#include <QThread>
#include <qmetaobject.h>
#include "csync.h"
namespace OCC {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
@@ -48,6 +50,14 @@ static void mirallLogCatcher(QtMsgType type, const QMessageLogContext &ctx, cons
}
#endif
static void csyncLogCatcher(int /*verbosity*/,
const char * /*function*/,
const char *buffer,
void * /*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
Logger *Logger::instance()
{
static Logger log;
@@ -55,7 +65,7 @@ Logger *Logger::instance()
}
Logger::Logger( QObject* parent) : QObject(parent),
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
_showTime(true), _logWindowActivated(false), _doFileFlush(false), _logExpire(0)
{
#ifndef NO_MSG_HANDLER
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
@@ -117,12 +127,8 @@ bool Logger::isNoop() const
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
return false;
#else
static auto signal = QMetaMethod::fromSignal(&Logger::newLog);
if (isSignalConnected(signal)) {
return false;
}
QMutexLocker lock(const_cast<QMutex *>(&_mutex));
return !_logstream;
return !_logstream && !_logWindowActivated;
#endif
}
@@ -136,7 +142,7 @@ void Logger::doLog(const QString& msg)
if( _doFileFlush ) _logstream->flush();
}
}
emit newLog(msg);
emit logWindowLog(msg);
}
void Logger::csyncLog( const QString& message )
@@ -164,10 +170,25 @@ void Logger::mirallLog( const QString& message )
Logger::instance()->log( log_ );
}
void Logger::setLogWindowActivated(bool activated)
{
QMutexLocker locker(&_mutex);
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback(csyncLogCatcher);
csync_set_log_level(11);
_logWindowActivated = activated;
}
void Logger::setLogFile(const QString & name)
{
QMutexLocker locker(&_mutex);
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback(csyncLogCatcher);
csync_set_log_level(11);
if( _logstream ) {
_logstream.reset(0);
_logFile.close();
+4 -2
Ver Arquivo
@@ -61,13 +61,15 @@ public:
void postOptionalGuiLog(const QString& title, const QString& message);
void postGuiMessage(const QString& title, const QString& message);
void setLogWindowActivated(bool activated);
void setLogFile( const QString & name );
void setLogExpire( int expire );
void setLogDir( const QString& dir );
void setLogFlush( bool flush );
signals:
void newLog(const QString&);
void logWindowLog(const QString&);
void guiLog(const QString&, const QString&);
void guiMessage(const QString&, const QString&);
void optionalGuiLog(const QString&, const QString&);
@@ -80,7 +82,7 @@ private:
~Logger();
QList<Log> _logs;
bool _showTime;
bool _doLogging;
bool _logWindowActivated;
QFile _logFile;
bool _doFileFlush;
int _logExpire;
+38 -1
Ver Arquivo
@@ -27,6 +27,7 @@
#include <QMutex>
#include <QDebug>
#include <QCoreApplication>
#include <QPixmap>
#include "json.h"
@@ -472,7 +473,7 @@ bool CheckServerJob::finished()
QVariantMap status = QtJson::parse(QString::fromUtf8(body), success).toMap();
// empty or invalid response
if (!success || status.isEmpty()) {
qDebug() << "status.php from server is not valid JSON!";
qDebug() << "status.php from server is not valid JSON!" << body << reply()->request().url();
}
qDebug() << "status.php returns: " << status << " " << reply()->error() << " Reply: " << reply();
@@ -589,6 +590,42 @@ bool PropfindJob::finished()
/*********************************************************************************************/
AvatarJob::AvatarJob(AccountPtr account, QObject *parent)
: AbstractNetworkJob(account, QString(), parent)
{
_avatarUrl = Utility::concatUrlPath(account->url(), QString("remote.php/dav/avatars/%1/128.png").arg(account->davUser()));
}
void AvatarJob::start()
{
QNetworkRequest req;
setReply(davRequest("GET", _avatarUrl, req));
setupConnections(reply());
AbstractNetworkJob::start();
}
bool AvatarJob::finished()
{
int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QPixmap avPixmap;
if (http_result_code == 200) {
QByteArray pngData = reply()->readAll();
if( pngData.size() ) {
if( avPixmap.loadFromData(pngData) ) {
qDebug() << "Retrieved Avatar pixmap!";
}
}
}
emit(avatarPixmap(avPixmap));
return true;
}
/*********************************************************************************************/
ProppatchJob::ProppatchJob(AccountPtr account, const QString &path, QObject *parent)
: AbstractNetworkJob(account, path, parent)
{
+30
Ver Arquivo
@@ -129,6 +129,36 @@ private:
QList<QByteArray> _properties;
};
/**
* @brief The AvatarJob class
*
* Retrieves the account users avatar from the server using a GET request.
*
* If the server does not have the avatar, the result Pixmap is empty.
*
* @ingroup libsync
*/
class OWNCLOUDSYNC_EXPORT AvatarJob : public AbstractNetworkJob {
Q_OBJECT
public:
explicit AvatarJob(AccountPtr account, QObject *parent = 0);
void start() Q_DECL_OVERRIDE;
signals:
/**
* @brief avatarPixmap - returns either a valid pixmap or not.
*/
void avatarPixmap(QPixmap);
private slots:
virtual bool finished() Q_DECL_OVERRIDE;
private:
QUrl _avatarUrl;
};
/**
* @brief Send a Proppatch request
*
+33 -34
Ver Arquivo
@@ -99,7 +99,7 @@ int OwncloudPropagator::hardMaximumActiveJob()
/** Updates, creates or removes a blacklist entry for the given item.
*
* Returns whether the file is in the blacklist now.
* Returns whether the error should be suppressed.
*/
static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
{
@@ -108,16 +108,13 @@ static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
if (newEntry.isValid()) {
journal->updateErrorBlacklistEntry(newEntry);
// Also clear upload info if any so we don't resume from the same transfer-id if there was too many failures (#5344)
// (maybe the reason is that the state for this transfer id is broken on the server.)
if (newEntry._retryCount > 3) {
journal->setUploadInfo(item._file, SyncJournalDb::UploadInfo());
}
} else if (oldEntry.isValid()) {
journal->wipeErrorBlacklistEntry(item._file);
}
return newEntry.isValid();
// In some cases we add errors to the blacklist for tracking, but don't
// want to actively suppress them.
return newEntry.isValid() && newEntry._ignoreDuration > 0;
}
void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
@@ -135,7 +132,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
}
}
if( _propagator->_abortRequested.fetchAndAddRelaxed(0) &&
if( propagator()->_abortRequested.fetchAndAddRelaxed(0) &&
(status == SyncFileItem::NormalError || status == SyncFileItem::FatalError)) {
// an abort request is ongoing. Change the status to Soft-Error
status = SyncFileItem::SoftError;
@@ -144,10 +141,12 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
switch( status ) {
case SyncFileItem::SoftError:
case SyncFileItem::FatalError:
// do not blacklist in case of soft error or fatal error.
break;
case SyncFileItem::NormalError:
if (blacklistCheck(_propagator->_journal, *_item) && _item->_hasBlacklistEntry) {
// For normal errors, we blacklist aggressively, otherwise only on
// explicit request.
if ((status == SyncFileItem::NormalError || _item->_errorMayBeBlacklisted)
&& blacklistCheck(propagator()->_journal, *_item)
&& _item->_hasBlacklistEntry) {
// do not error if the item was, and continues to be, blacklisted
status = SyncFileItem::FileIgnored;
_item->_errorString.prepend(tr("Continue blacklisting:") + " ");
@@ -157,10 +156,10 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
case SyncFileItem::Restoration:
if( _item->_hasBlacklistEntry ) {
// wipe blacklist entry.
_propagator->_journal->wipeErrorBlacklistEntry(_item->_file);
propagator()->_journal->wipeErrorBlacklistEntry(_item->_file);
// remove a blacklist entry in case the file was moved.
if( _item->_originalFile != _item->_file ) {
_propagator->_journal->wipeErrorBlacklistEntry(_item->_originalFile);
propagator()->_journal->wipeErrorBlacklistEntry(_item->_originalFile);
}
}
break;
@@ -187,7 +186,7 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
{
PropagateItemJob *newJob = NULL;
if( httpStatusCode == 403 && _propagator->isInSharedDirectory(_item->_file )) {
if( httpStatusCode == 403 && propagator()->isInSharedDirectory(_item->_file )) {
if( !_item->_isDirectory ) {
SyncFileItemPtr downloadItem(new SyncFileItem(*_item));
if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW
@@ -206,18 +205,18 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
downloadItem->_instruction = CSYNC_INSTRUCTION_SYNC;
}
downloadItem->_direction = SyncFileItem::Down;
newJob = new PropagateDownloadFile(_propagator, downloadItem);
newJob = new PropagateDownloadFile(propagator(), downloadItem);
} else {
// Directories are harder to recover.
// But just re-create the directory, next sync will be able to recover the files
SyncFileItemPtr mkdirItem(new SyncFileItem(*_item));
mkdirItem->_instruction = CSYNC_INSTRUCTION_NEW;
mkdirItem->_direction = SyncFileItem::Down;
newJob = new PropagateLocalMkdir(_propagator, mkdirItem);
newJob = new PropagateLocalMkdir(propagator(), mkdirItem);
// Also remove the inodes and fileid from the db so no further renames are tried for
// this item.
_propagator->_journal->avoidRenamesOnNextSync(_item->_file);
_propagator->_anotherSyncNeeded = true;
propagator()->_journal->avoidRenamesOnNextSync(_item->_file);
propagator()->_anotherSyncNeeded = true;
}
if( newJob ) {
newJob->setRestoreJobMsg(msg);
@@ -277,7 +276,7 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItemPtr &item) {
} else {
PropagateUploadFileCommon *job = 0;
if (item->_size > chunkSize() && account()->capabilities().chunkingNg()) {
job = new PropagateUploadFileNG(this, item, account()->capabilities().requestMaxDurationDC());
job = new PropagateUploadFileNG(this, item);
} else {
job = new PropagateUploadFileV1(this, item);
}
@@ -459,18 +458,6 @@ quint64 OwncloudPropagator::chunkSize()
return chunkSize;
}
quint64 OwncloudPropagator::maxChunkSize()
{
static uint chunkSize;
if (!chunkSize) {
chunkSize = qgetenv("OWNCLOUD_MAX_CHUNK_SIZE").toUInt();
if (chunkSize == 0) {
ConfigFile cfg;
chunkSize = cfg.maxChunkSize();
}
}
return chunkSize;
}
bool OwncloudPropagator::localFileNameClash( const QString& relFile )
{
@@ -586,6 +573,18 @@ OwncloudPropagator::DiskSpaceResult OwncloudPropagator::diskSpaceCheck() const
// ================================================================================
PropagatorJob::PropagatorJob(OwncloudPropagator *propagator)
: QObject(propagator)
, _state(NotYetStarted)
{
}
OwncloudPropagator *PropagatorJob::propagator() const
{
return qobject_cast<OwncloudPropagator*>(parent());
}
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
{
// If any of the non-finished sub jobs is not parallel, we have to wait
@@ -701,7 +700,7 @@ void PropagateDirectory::finalize()
if(_item->_instruction == CSYNC_INSTRUCTION_RENAME
&& _item->_originalFile != _item->_renameTarget) {
// Remove the stale entries from the database.
_propagator->_journal->deleteFileRecord(_item->_originalFile, true);
propagator()->_journal->deleteFileRecord(_item->_originalFile, true);
}
_item->_file = _item->_renameTarget;
@@ -719,8 +718,8 @@ void PropagateDirectory::finalize()
_item->_fileId = mkdir->_item->_fileId;
}
}
SyncJournalFileRecord record(*_item, _propagator->_localDir + _item->_file);
ok = _propagator->_journal->setFileRecordMetadata(record);
SyncJournalFileRecord record(*_item, propagator()->_localDir + _item->_file);
ok = propagator()->_journal->setFileRecordMetadata(record);
if (!ok) {
_hasError = _item->_status = SyncFileItem::FatalError;
_item->_errorString = tr("Error writing metadata to the database");

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