summaryrefslogtreecommitdiff
path: root/sfx2
diff options
context:
space:
mode:
authorGiuseppe Castagno <giuseppe.castagno@acca-esse.eu>2015-08-28 18:52:36 +0200
committerJan Holesovsky <kendy@collabora.com>2015-10-05 11:14:50 +0000
commitb4576f3da4d90139fc5140962d13cb91dab98797 (patch)
tree12f4d4a16e0c6d5d9c9995315da37b96c6629a87 /sfx2
parent8ea85c264f22c76d393c0f78e9db7df51e2c868d (diff)
tdf#82744: fix WebDAV lock/unlock behaviour - part 3
Changes done to the code in sfx2, ucbhelper, ucb, unotools in no particular order - add method helpers to call the ucb lock/unlock - add lock/unlock 'real' management - make DateChange property retrieval working for WebDAV as well - add check for changed content of a WebDAV file, in order to reload it correctly when 'Edit Mode' command is activated from GUI - Unlock WebDAV file while saving only if explicitly enabled Needed in order to avoid the small window of file unlocked state that opens while saving a file. When saving LO actually does as follows: - unlock the prevoius version of the file - prepares operations to save the modified version - lock the new file - save the new version - the lock method is enabled if the DAV resource supports it. In case the lock is not supported, for example example DAV with lock disabled, the lock method is disabled. Exception: when the resource is first created and the lock is not supported: a lock command is sent anyway, because if the resource is not yet present, there is no method to detect the lock/unlock availability in this case. - cppcheck:noExplicitConstructor Change-Id: I0aa876c4e3364d86e5740977b97f3db9a01e4491 Reviewed-on: https://gerrit.libreoffice.org/17189 Reviewed-by: Jan Holesovsky <kendy@collabora.com> Tested-by: Jan Holesovsky <kendy@collabora.com>
Diffstat (limited to 'sfx2')
-rw-r--r--sfx2/source/doc/docfile.cxx146
-rw-r--r--sfx2/source/doc/objstor.cxx8
-rw-r--r--sfx2/source/view/viewfrm.cxx32
3 files changed, 174 insertions, 12 deletions
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 26f4820a8ee0..ccdad939071e 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -41,6 +41,8 @@
#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
#include <com/sun/star/ucb/CommandFailedException.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
+#include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
+#include <com/sun/star/ucb/Lock.hpp>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
#include <com/sun/star/ucb/XContentProvider.hpp>
@@ -181,6 +183,7 @@ public:
bool m_bSalvageMode:1;
bool m_bVersionsAlreadyLoaded:1;
bool m_bLocked:1;
+ bool m_bDisableUnlockWebDAV:1;
bool m_bGotDateTime:1;
bool m_bRemoveBackup:1;
bool m_bOriginallyReadOnly:1;
@@ -257,6 +260,7 @@ SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP ) :
m_bSalvageMode( false ),
m_bVersionsAlreadyLoaded( false ),
m_bLocked( false ),
+ m_bDisableUnlockWebDAV( false ),
m_bGotDateTime( false ),
m_bRemoveBackup( false ),
m_bOriginallyReadOnly(false),
@@ -381,7 +385,8 @@ void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
bool SfxMedium::DocNeedsFileDateCheck() const
{
- return !IsReadOnly() && GetURLObject().GetProtocol() == INetProtocol::File;
+ return ( !IsReadOnly() && ( GetURLObject().GetProtocol() == INetProtocol::File ||
+ GetURLObject().isAnyKnownWebDAVScheme() ) );
}
util::DateTime SfxMedium::GetInitFileDate( bool bIgnoreOldValue )
@@ -942,6 +947,100 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
(void) bLoading;
(void) bNoUI;
#else
+ // check if path scheme is http:// or https://
+ // may be this is better if used always, in Android and iOS as well?
+ // if this code should be always there, remember to move the relevant code in UnlockFile method as well !
+
+ if ( GetURLObject().isAnyKnownWebDAVScheme() )
+ {
+ try
+ {
+ bool bResult = pImp->m_bLocked;
+ // so, this is webdav stuff...
+ if ( !bResult )
+ {
+ // no read-write access is necessary on loading if the document is explicitly opened as copy
+ SFX_ITEMSET_ARG( GetItemSet(), pTemplateItem, SfxBoolItem, SID_TEMPLATE, false );
+ bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
+ }
+
+ if ( !bResult && !IsReadOnly() )
+ {
+ sal_Int8 bUIStatus = LOCK_UI_NOLOCK;
+ do
+ {
+ if( !bResult )
+ {
+ Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
+ uno::Reference< task::XInteractionHandler > xCHandler = GetInteractionHandler( true );
+ xComEnv = new ::ucbhelper::CommandEnvironment(
+ xCHandler, Reference< ::com::sun::star::ucb::XProgressHandler >() );
+
+ ucbhelper::Content aContentToLock(
+ GetURLObject().GetMainURL( INetURLObject::NO_DECODE ),
+ xComEnv, comphelper::getProcessComponentContext() );
+
+ try
+ {
+ aContentToLock.lock();
+ bResult = true;
+ }
+ catch ( ucb::InteractiveLockingLockedException& )
+ {
+ // received when the resource is already locked
+ // get the lock owner, using a special ucb.webdav property
+ // the owner property retrieved here is what the other principal send the server
+ // when activating the lock.
+ // See http://tools.ietf.org/html/rfc4918#section-14.17 for details
+ LockFileEntry aLockData;
+ aLockData[LockFileComponent::OOOUSERNAME] = OUString("Unknown user");
+
+ uno::Sequence< ::com::sun::star::ucb::Lock > aLocks;
+ if( aContentToLock.getPropertyValue( "DAV:lockdiscovery" ) >>= aLocks )
+ {
+ // got at least a lock, show the owner of the first lock returned
+ ::com::sun::star::ucb::Lock aLock = aLocks[0];
+ OUString aOwner;
+ if(aLock.Owner >>= aOwner)
+ aLockData[LockFileComponent::OOOUSERNAME] = aOwner;
+ }
+
+ if ( !bResult && !bNoUI )
+ {
+ bUIStatus = ShowLockedDocumentDialog( aLockData, bLoading, false );
+ }
+ }
+ catch( uno::Exception& )
+ {}
+ }
+ } while( !bResult && bUIStatus == LOCK_UI_TRY );
+ }
+
+ pImp->m_bLocked = bResult;
+
+ if ( !bResult && GetError() == ERRCODE_NONE )
+ {
+ // the error should be set in case it is storing process
+ // or the document has been opened for editing explicitly
+ SFX_ITEMSET_ARG( pImp->m_pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, false );
+
+ if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
+ SetError( ERRCODE_IO_ACCESSDENIED, OUString( OSL_LOG_PREFIX ) );
+ else
+ GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
+ }
+
+ // when the file is locked, get the current file date
+ if ( bResult && DocNeedsFileDateCheck() )
+ GetInitFileDate( true );
+ }
+ catch ( const uno::Exception& )
+ {
+ SAL_WARN( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
+ }
+ return;
+ }
+
if (!IsLockingUsed() || GetURLObject().HasError())
return;
@@ -2305,8 +2404,15 @@ void SfxMedium::GetMedium_Impl()
aMedium.addInputStreamOwnLock();
}
else
+ {
+ // add a check for protocol, if it's http or https or provate webdav then add
+ // the interaction handler to be used by the authentication dialog
+ if ( GetURLObject().isAnyKnownWebDAVScheme() )
+ {
+ aMedium[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()] <<= GetInteractionHandler( true );
+ }
aMedium.addInputStream();
-
+ }
// the ReadOnly property set in aMedium is ignored
// the check is done in LockOrigFileOnDemand() for file and non-file URLs
@@ -2500,10 +2606,10 @@ void SfxMedium::UseInteractionHandler( bool bUse )
::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
-SfxMedium::GetInteractionHandler()
+SfxMedium::GetInteractionHandler( bool bGetAlways )
{
// if interaction isn't allowed explicitly ... return empty reference!
- if ( !pImp->bUseInteractionHandler )
+ if ( !bGetAlways && !pImp->bUseInteractionHandler )
return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
// search a possible existing handler inside cached item set
@@ -2516,7 +2622,7 @@ SfxMedium::GetInteractionHandler()
}
// if default interaction isn't allowed explicitly ... return empty reference!
- if ( !pImp->bAllowDefaultIntHdl )
+ if ( !bGetAlways && !pImp->bAllowDefaultIntHdl )
return ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >();
// otherwise return cached default handler ... if it exist.
@@ -2597,11 +2703,41 @@ void SfxMedium::CloseAndRelease()
UnlockFile( true );
}
+void SfxMedium::DisableUnlockWebDAV( bool bDisableUnlockWebDAV )
+{
+ pImp->m_bDisableUnlockWebDAV = bDisableUnlockWebDAV;
+}
+
void SfxMedium::UnlockFile( bool bReleaseLockStream )
{
#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
(void) bReleaseLockStream;
#else
+ // check if webdav
+ if ( GetURLObject().isAnyKnownWebDAVScheme() )
+ {
+ if ( pImp->m_bLocked )
+ {
+ // an interaction handler should be used for authentication, if needed
+ try {
+ uno::Reference< ::com::sun::star::task::XInteractionHandler > xHandler = GetInteractionHandler( true );
+ uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
+ xComEnv = new ::ucbhelper::CommandEnvironment( xHandler,
+ Reference< ::com::sun::star::ucb::XProgressHandler >() );
+ ucbhelper::Content aContentToUnlock( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xComEnv, comphelper::getProcessComponentContext());
+ pImp->m_bLocked = false;
+ //check if WebDAV unlock was explicitly disabled
+ if ( !pImp->m_bDisableUnlockWebDAV )
+ aContentToUnlock.unlock();
+ }
+ catch ( uno::Exception& )
+ {
+ SAL_WARN( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
+ }
+ }
+ return;
+ }
+
if ( pImp->m_xLockingStream.is() )
{
if ( bReleaseLockStream )
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 312b4405530f..e3682e305759 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -1774,6 +1774,9 @@ bool SfxObjectShell::SaveTo_Impl
}
+// This method contains a call to disable the UNLOCK of a WebDAV resource, that work while saving a file.
+// If the method is called from another process (e.g. not when saving a file),
+// that disabling needs tweaking
bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& rTargetMedium )
{
// this method disconnects the storage from source medium, and attaches it to the backup created by the target medium
@@ -1794,7 +1797,12 @@ bool SfxObjectShell::DisconnectStorage_Impl( SfxMedium& rSrcMedium, SfxMedium& r
rTargetMedium.ResetError();
xOptStorage->writeAndAttachToStream( uno::Reference< io::XStream >() );
rSrcMedium.CanDisposeStorage_Impl( false );
+ // need to modify this for WebDAV if this method is called outside
+ // the process of saving a file
+ rSrcMedium.DisableUnlockWebDAV();
rSrcMedium.Close();
+ // see comment on the previou third row
+ rSrcMedium.DisableUnlockWebDAV( false );
// now try to create the backup
rTargetMedium.GetBackup_Impl();
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 33c96235379d..6cce9411dfe7 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -432,13 +432,31 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
INetURLObject aMedObj( pMed->GetName() );
- // the logic below is following, if the document seems not to need to be reloaded and the physical name is different
- // to the logical one, then on file system it can be checked that the copy is still newer than the original and no document reload is required
- if ( ( !bNeedsReload && ( (aMedObj.GetProtocol() == INetProtocol::File &&
- aMedObj.getFSysPath(INetURLObject::FSYS_DETECT) != aPhysObj.getFSysPath(INetURLObject::FSYS_DETECT) &&
- !::utl::UCBContentHelper::IsYounger( aMedObj.GetMainURL( INetURLObject::NO_DECODE ), aPhysObj.GetMainURL( INetURLObject::NO_DECODE ) ))
- || pMed->IsRemote() ) )
- || pVersionItem )
+ // -> tdf#82744
+ // the logic below is following:
+ // if the document seems not to need to be reloaded
+ // and the physical name is different to the logical one,
+ // then on file system it can be checked that the copy is still newer than the original and no document reload is required.
+ // Did some semplification to enhance readability of the 'if' expression
+ //
+ // when the 'http/https' protocol is active, the bool bPhysObjIsYounger relies upon the getlastmodified Property of a WebDAV resource.
+ // Said property should be implemented, but sometimes it's not.
+ // implemented. On this case the reload activated here will not work properly.
+ // TODO: change the check age method for WebDAV to etag (entity-tag) property value, need some rethinking, since the
+ // etag tells that the cache representation (e.g. in LO) is different from the one on the server,
+ // but tells nothing about the age
+ // Details at this link: http://tools.ietf.org/html/rfc4918#section-15, section 15.7
+ bool bPhysObjIsYounger = ::utl::UCBContentHelper::IsYounger( aMedObj.GetMainURL( INetURLObject::NO_DECODE ),
+ aPhysObj.GetMainURL( INetURLObject::NO_DECODE ) );
+ bool bIsWebDAV = aMedObj.isAnyKnownWebDAVScheme();
+
+ if ( ( !bNeedsReload && ( ( aMedObj.GetProtocol() == INetProtocol::File &&
+ aMedObj.getFSysPath( INetURLObject::FSYS_DETECT ) != aPhysObj.getFSysPath( INetURLObject::FSYS_DETECT ) &&
+ !bPhysObjIsYounger )
+ || ( bIsWebDAV && !bPhysObjIsYounger )
+ || ( pMed->IsRemote() && !bIsWebDAV ) ) )
+ || pVersionItem )
+ // <- tdf#82744
{
bool bOK = false;
if ( !pVersionItem )