ooo-build r13641 - in trunk: . patches/dev300
- From: jholesovsky svn gnome org
- To: svn-commits-list gnome org
- Subject: ooo-build r13641 - in trunk: . patches/dev300
- Date: Wed, 20 Aug 2008 14:48:05 +0000 (UTC)
Author: jholesovsky
Date: Wed Aug 20 14:48:05 2008
New Revision: 13641
URL: http://svn.gnome.org/viewvc/ooo-build?rev=13641&view=rev
Log:
2008-08-20 Jan Holesovsky <kendy suse cz>
* patches/dev300/webdav-locking-refresh-lock.diff: Not needed any
more.
* patches/dev300/webdav-locking-from-ooo-build-2-4-1.diff,
patches/dev300/apply: Forward ported all the webdav-locking patches
from ooo-build-2-4-1 to have something stable for 3.0 ;-)
Added:
trunk/patches/dev300/webdav-locking-from-ooo-build-2-4-1.diff
Removed:
trunk/patches/dev300/webdav-locking-refresh-lock.diff
Modified:
trunk/ChangeLog
trunk/patches/dev300/apply
Modified: trunk/patches/dev300/apply
==============================================================================
--- trunk/patches/dev300/apply (original)
+++ trunk/patches/dev300/apply Wed Aug 20 14:48:05 2008
@@ -522,6 +522,8 @@
[ WebDAVUpstream ]
+SectionOwner => jholesov
+SectionIssue => i#29152
# WebDAV locking implementation - the up-stream version
cws-webdavandgvfslocking1-comphelper.diff
cws-webdavandgvfslocking1-officecfg.diff
@@ -533,12 +535,12 @@
cws-webdavandgvfslocking1-unotools.diff
[ WebDAV ]
+SectionOwner => jholesov
+SectionIssue => i#29152
# WebDAV locking implementation - the original version
-# don't lock for infinite, instead set timeout to 3 minutes, and refresh 30
-# sec before expiration
-# FIXME this is now part of cws-webdavandgvfslocking1-ucb.diff
-# FIXME remove after copied to ooo-build-2-4-1
-#webdav-locking-refresh-lock.diff, n#403724, jholesov
+# This is forward-ported from ooo-build-2-4-1, because the version for
+# up-streaming still does not work as expected :-(
+webdav-locking-from-ooo-build-2-4-1.diff
[ GnomeVFS ]
@@ -2524,3 +2526,4 @@
[ Fixes >= dev300-m30 >= ooo300-m3 ]
pdfimport-system-poppler.diff, i#92920, cmc
+
Added: trunk/patches/dev300/webdav-locking-from-ooo-build-2-4-1.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/webdav-locking-from-ooo-build-2-4-1.diff Wed Aug 20 14:48:05 2008
@@ -0,0 +1,2765 @@
+diff --git officecfg/registry/data/org/openoffice/ucb/Configuration.xcu officecfg/registry/data/org/openoffice/ucb/Configuration.xcu
+index 988a475..c822331 100644
+--- officecfg/registry/data/org/openoffice/ucb/Configuration.xcu
++++ officecfg/registry/data/org/openoffice/ucb/Configuration.xcu
+@@ -178,6 +178,28 @@
+ <value/>
+ </prop>
+ </node>
++ <node oor:name="Provider14" oor:op="replace">
++ <prop oor:name="ServiceName">
++ <value>com.sun.star.ucb.WebDAVContentProvider</value>
++ </prop>
++ <prop oor:name="URLTemplate">
++ <value>webdav</value>
++ </prop>
++ <prop oor:name="Arguments">
++ <value/>
++ </prop>
++ </node>
++ <node oor:name="Provider15" oor:op="replace">
++ <prop oor:name="ServiceName">
++ <value>com.sun.star.ucb.WebDAVContentProvider</value>
++ </prop>
++ <prop oor:name="URLTemplate">
++ <value>webdavs</value>
++ </prop>
++ <prop oor:name="Arguments">
++ <value/>
++ </prop>
++ </node>
+ <!-- We want the Provider to be the final fallback provider -->
+ <node oor:name="Provider999" oor:op="replace" install:module="gio">
+ <prop oor:name="ServiceName">
+diff --git sal/inc/osl/file.h sal/inc/osl/file.h
+index 482004f..e5b35e4 100644
+--- sal/inc/osl/file.h
++++ sal/inc/osl/file.h
+@@ -139,6 +139,7 @@ typedef enum {
+ osl_File_E_USERS,
+ osl_File_E_OVERFLOW,
+ osl_File_E_NOTREADY,
++ osl_File_E_TXTBSY,
+ osl_File_E_invalidError, /* unmapped error: always last entry in enum! */
+ osl_File_E_TIMEDOUT,
+ osl_File_E_NETWORK,
+diff --git sal/inc/osl/file.hxx sal/inc/osl/file.hxx
+index 26f2645..e989ff8 100644
+--- sal/inc/osl/file.hxx
++++ sal/inc/osl/file.hxx
+@@ -106,6 +106,7 @@ public:
+ E_USERS = osl_File_E_USERS,
+ E_OVERFLOW = osl_File_E_OVERFLOW,
+ E_NOTREADY = osl_File_E_NOTREADY,
++ E_TXTBSY = osl_File_E_TXTBSY,
+ E_invalidError = osl_File_E_invalidError, /* unmapped error: always last entry in enum! */
+ E_TIMEDOUT = osl_File_E_TIMEDOUT,
+ E_NETWORK = osl_File_E_NETWORK
+diff --git sal/osl/unx/file_error_transl.cxx sal/osl/unx/file_error_transl.cxx
+index 5333cfe..4ffa6be 100644
+--- sal/osl/unx/file_error_transl.cxx
++++ sal/osl/unx/file_error_transl.cxx
+@@ -247,6 +247,10 @@ oslFileError oslTranslateFileError(sal_Bool bIsError, int Errno)
+ osl_error = osl_File_E_TIMEDOUT;
+ break;
+
++ case ETXTBSY:
++ osl_error = osl_File_E_TXTBSY;
++ break;
++
+ default:
+ /* FIXME translateFileError: is this alright? Or add a new one: osl_File_E_Unknown? */
+ osl_error = osl_File_E_invalidError;
+diff --git sc/source/ui/docshell/docsh.cxx sc/source/ui/docshell/docsh.cxx
+index 07e68a5..8591efa 100644
+--- sc/source/ui/docshell/docsh.cxx
++++ sc/source/ui/docshell/docsh.cxx
+@@ -1025,7 +1025,7 @@ BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium )
+ // Alle Filter brauchen die komplette Datei am Stueck (nicht asynchron),
+ // darum vorher per CreateFileStream dafuer sorgen, dass die komplette
+ // Datei uebertragen wird.
+- rMedium.GetPhysicalName(); //! CreateFileStream direkt rufen, wenn verfuegbar
++ rMedium.GetPhysicalName( sal_False ); //! CreateFileStream direkt rufen, wenn verfuegbar
+
+ SFX_ITEMSET_ARG( rMedium.GetItemSet(), pUpdateDocItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False);
+ nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : com::sun::star::document::UpdateDocMode::NO_UPDATE;
+diff --git sfx2/inc/sfx2/docfile.hxx sfx2/inc/sfx2/docfile.hxx
+index 219cf18..b548b22 100644
+--- sfx2/inc/sfx2/docfile.hxx
++++ sfx2/inc/sfx2/docfile.hxx
+@@ -181,7 +181,7 @@ public:
+ const INetURLObject& GetURLObject() const;
+ #endif
+ ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContent > GetContent() const;
+- const String& GetPhysicalName() const;
++ const String& GetPhysicalName( sal_Bool bForceCreateTempIfRemote = sal_True ) const;
+ void SetTemporary( sal_Bool bTemp );
+ sal_Bool IsTemporary() const;
+ sal_Bool IsRemote();
+@@ -254,6 +254,8 @@ public:
+ void SetCharset( ::rtl::OUString );
+ ::rtl::OUString GetBaseURL( bool bForSaving=false );
+
++ sal_Bool SupportsActiveStreaming( const rtl::OUString &rName ) const;
++
+ #if _SOLAR__PRIVATE
+ //REMOVE // the storage will be truncated, if it is still not open then the stream will be truncated
+ //REMOVE ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > GetOutputStorage_Impl();
+diff --git sfx2/source/bastyp/helper.cxx sfx2/source/bastyp/helper.cxx
+index 3e08e8a..2206cc9 100644
+--- sfx2/source/bastyp/helper.cxx
++++ sfx2/source/bastyp/helper.cxx
+@@ -796,16 +796,15 @@ ErrCode SfxContentHelper::QueryDiskSpace( const String& rPath, sal_Int64& rFreeB
+
+ // -----------------------------------------------------------------------
+
+-ULONG SfxContentHelper::GetSize( const String& rContent )
++sal_Int64 SfxContentHelper::GetSize( const String& rContent )
+ {
+- ULONG nSize = 0;
+- sal_Int64 nTemp = 0;
++ sal_Int64 nSize = -1;
+ INetURLObject aObj( rContent );
+ DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
+ try
+ {
+ ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ucb::XCommandEnvironment > () );
+- aCnt.getPropertyValue( OUString::createFromAscii( "Size" ) ) >>= nTemp;
++ aCnt.getPropertyValue( OUString::createFromAscii( "Size" ) ) >>= nSize;
+ }
+ catch( ucb::CommandAbortedException& )
+ {
+@@ -815,7 +814,6 @@ ULONG SfxContentHelper::GetSize( const String& rContent )
+ {
+ DBG_ERRORFILE( "Any other exception" );
+ }
+- nSize = (UINT32)nTemp;
+ return nSize;
+ }
+
+diff --git sfx2/source/dialog/dinfdlg.cxx sfx2/source/dialog/dinfdlg.cxx
+index 7455a59..075f9ee 100644
+--- sfx2/source/dialog/dinfdlg.cxx
++++ sfx2/source/dialog/dinfdlg.cxx
+@@ -1066,8 +1066,9 @@ void SfxDocumentPage::Reset( const SfxItemSet& rSet )
+
+ // determine size and type
+ String aSizeText( aUnknownSize );
+- if ( aURL.GetProtocol() == INET_PROT_FILE )
+- aSizeText = CreateSizeText( SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::NO_DECODE ) ) );
++ sal_Int64 nSize = SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
++ if ( nSize >= 0 )
++ aSizeText = CreateSizeText( static_cast< ULONG >( nSize ) );
+ aShowSizeFT.SetText( aSizeText );
+
+ String aDescription = SvFileInformationManager::GetDescription( INetURLObject(rMainURL) );
+diff --git sfx2/source/doc/docfile.cxx sfx2/source/doc/docfile.cxx
+index 44bf761..d80a13b 100644
+--- sfx2/source/doc/docfile.cxx
++++ sfx2/source/doc/docfile.cxx
+@@ -653,10 +653,13 @@ sal_Bool SfxMedium::CloseOutStream_Impl()
+ }
+
+ //------------------------------------------------------------------
+-const String& SfxMedium::GetPhysicalName() const
++const String& SfxMedium::GetPhysicalName( sal_Bool bForceCreateTempIfRemote ) const
+ {
+ if ( !aName.Len() && aLogicName.Len() )
+- (( SfxMedium*)this)->CreateFileStream();
++ {
++ if ( bForceCreateTempIfRemote || !SupportsActiveStreaming( aLogicName ) )
++ (( SfxMedium*)this)->CreateFileStream();
++ }
+
+ // return the name then
+ return aName;
+@@ -822,11 +825,31 @@ sal_Bool SfxMedium::TryStorage()
+ }
+
+ //------------------------------------------------------------------
++sal_Bool SfxMedium::SupportsActiveStreaming( const rtl::OUString &rName ) const
++{
++ if ( ::utl::LocalFileHelper::IsLocalFile( rName ) )
++ return sal_True;
++
++ ::ucbhelper::Content aTmpContent;
++ Reference< ::com::sun::star::ucb::XCommandEnvironment > xDummyEnv;
++ if ( ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), xDummyEnv, aTmpContent ) )
++ {
++ Any aAny = aTmpContent.getPropertyValue(
++ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "SupportsActiveStreaming" )) );
++
++ sal_Bool bSupportsStreaming = sal_False;
++ return ( ( aAny >>= bSupportsStreaming ) && bSupportsStreaming );
++ }
++
++ return sal_False;
++}
++
++//------------------------------------------------------------------
+ sal_Bool SfxMedium::BasedOnOriginalFile_Impl()
+ {
+ return ( !pImp->pTempFile && !( aLogicName.Len() && pImp->m_bSalvageMode )
+ && GetURLObject().GetMainURL( INetURLObject::NO_DECODE ).getLength()
+- && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
++ && SupportsActiveStreaming( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) )
+ && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) );
+ }
+
+@@ -892,7 +915,7 @@ uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
+
+ // medium based on OutputStream: must work with TempFile
+ if( aLogicName.CompareToAscii( "private:stream", 14 ) == COMPARE_EQUAL
+- || !::utl::LocalFileHelper::IsLocalFile( aLogicName ) )
++ || !SupportsActiveStreaming( aLogicName ) )
+ CreateTempFileNoCopy();
+ // if Medium already contains a stream - TODO/LATER: store stream/outputstream in ImplData, not in Medium
+ else if ( GetItemSet()->GetItemState( SID_STREAM ) < SFX_ITEM_SET )
+@@ -1165,7 +1188,7 @@ uno::Reference < embed::XStorage > SfxMedium::GetStorage()
+
+ try
+ {
+- if ( IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( aLogicName ) )
++ if ( IsReadOnly() && SupportsActiveStreaming( aLogicName ) )
+ {
+ //TODO/LATER: performance problem if not controlled by special Mode in SfxMedium
+ //(should be done only for permanently open storages)
+@@ -1982,7 +2005,7 @@ void SfxMedium::Transfer_Impl()
+ xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
+ Reference< ::com::sun::star::ucb::XProgressHandler >() );
+
+- if ( ::utl::LocalFileHelper::IsLocalFile( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) || !aDest.removeSegment() )
++ if ( SupportsActiveStreaming( aDest.GetMainURL( INetURLObject::NO_DECODE ) ) || !aDest.removeSegment() )
+ {
+ TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
+ }
+diff --git sfx2/source/inc/helper.hxx sfx2/source/inc/helper.hxx
+index f37477d..1f46ed7 100644
+--- sfx2/source/inc/helper.hxx
++++ sfx2/source/inc/helper.hxx
+@@ -69,7 +69,7 @@ public:
+
+ static sal_Bool MakeFolder( const String& rFolder );
+ static ErrCode QueryDiskSpace( const String& rPath, sal_Int64& rFreeBytes );
+- static ULONG GetSize( const String& rContent );
++ static sal_Int64 GetSize( const String& rContent );
+ static sal_Bool IsYounger( const String& rIsYoung, const String& rIsOlder );
+
+ // please don't use this!
+diff --git sfx2/source/view/viewfrm.cxx sfx2/source/view/viewfrm.cxx
+index c19a833..160fe9b 100644
+--- sfx2/source/view/viewfrm.cxx
++++ sfx2/source/view/viewfrm.cxx
+@@ -626,6 +626,11 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
+ sal_Bool bHandsOff =
+ ( pMedium->GetURLObject().GetProtocol() == INET_PROT_FILE && !xOldObj->IsDocShared() );
+
++ // we must do the same for the contents that support active
++ // streaming
++ if ( !bHandsOff && pMedium && pMedium->SupportsActiveStreaming( aURL ) )
++ bHandsOff = sal_True;
++
+ // bestehende SfxMDIFrames f"ur dieses Doc leeren
+ // eigenes Format oder R/O jetzt editierbar "offnen?
+ SfxViewNotificatedFrameList_Impl aFrames;
+diff --git tools/inc/tools/urlobj.hxx tools/inc/tools/urlobj.hxx
+index 10202ab..2ab1459 100644
+--- tools/inc/tools/urlobj.hxx
++++ tools/inc/tools/urlobj.hxx
+@@ -141,9 +141,14 @@ enum INetProtocol
+ INET_PROT_TELNET = 28,
+ INET_PROT_VND_SUN_STAR_EXPAND = 29,
+ INET_PROT_VND_SUN_STAR_TDOC = 30,
+- INET_PROT_GENERIC = 31,
+- INET_PROT_SMB = 32,
+- INET_PROT_END = 33
++ INET_PROT_SMB = 31,
++ INET_PROT_DAV = 32,
++ INET_PROT_DAVS = 33,
++ INET_PROT_WEBDAV = 34,
++ INET_PROT_WEBDAVS = 35,
++ INET_PROT_GENERIC = 36,
++ INET_PROT_GENERIC_HIERARCHICAL = 37,
++ INET_PROT_END = 38
+ };
+
+ //============================================================================
+diff --git tools/source/fsys/urlobj.cxx tools/source/fsys/urlobj.cxx
+index f195b18..55aa073 100644
+--- tools/source/fsys/urlobj.cxx
++++ tools/source/fsys/urlobj.cxx
+@@ -374,21 +374,21 @@ static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END]
+ false },
+ { "ftp", "ftp://", 21, true, true, false, true, true, true, true,
+ false },
+- { "http", "http://", 80, true, false, false, false, true, true,
++ { "http", "http://", 80, true, true, false, true, true, true,
+ true, true },
+ { "file", "file://", 0, true, false, false, false, true, false,
+ true, false },
+ { "mailto", "mailto:", 0, false, false, false, false, false,
+ false, false, true },
+- { "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, false,
+- false, false, true, true, true, true },
++ { "vnd.sun.star.webdav", "vnd.sun.star.webdav://", 80, true, true,
++ false, true, true, true, true, true },
+ { "news", "news:", 0, false, false, false, false, false, false, false,
+ false },
+ { "private", "private:", 0, false, false, false, false, false,
+ false, false, true },
+ { "vnd.sun.star.help", "vnd.sun.star.help://", 0, true, false, false,
+ false, false, false, true, true },
+- { "https", "https://", 443, true, false, false, false, true, true,
++ { "https", "https://", 443, true, true, false, true, true, true,
+ true, true },
+ { "slot", "slot:", 0, false, false, false, false, false, false,
+ false, true },
+@@ -432,9 +432,19 @@ static INetURLObject::SchemeInfo const aSchemeInfoMap[INET_PROT_END]
+ false, false, false, false, false },
+ { "vnd.sun.star.tdoc", "vnd.sun.star.tdoc:", 0, false, false, false,
+ false, false, false, true, false },
+- { "", "", 0, false, false, false, false, false, false, false, false },
+ { "smb", "smb://", 139, true, true, false, true, true, true, true,
+- true } };
++ true },
++ { "dav", "dav://", 80, true, true, false, true, true, true, true,
++ true },
++ { "davs", "davs://", 443, true, true, false, true, true, true,
++ true, true },
++ { "webdav", "webdav://", 80, true, true, false, true, true, true, true,
++ true },
++ { "webdavs", "webdavs://", 443, true, true, false, true, true, true,
++ true, true },
++ { "", "", 0, false, false, false, false, false, false, false, false },
++ { "", "", 0, false, false, false, false, false, false, true, false }
++ };
+
+ // static
+ inline INetURLObject::SchemeInfo const &
+@@ -847,7 +857,10 @@ bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef,
+ aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter);
+ if (aSynScheme.getLength() > 0)
+ {
+- m_eScheme = INET_PROT_GENERIC;
++ if (p1 != pEnd && *p1 == '/')
++ m_eScheme = INET_PROT_GENERIC_HIERARCHICAL;
++ else
++ m_eScheme = INET_PROT_GENERIC;
+ pPos = p1;
+ }
+ }
+@@ -864,8 +877,9 @@ bool INetURLObject::setAbsURIRef(rtl::OUString const & rTheAbsURIRef,
+ return false;
+ }
+
+- if (m_eScheme != INET_PROT_GENERIC) {
+- aSynScheme = rtl::OUString::createFromAscii(getSchemeInfo().m_pScheme);
++ const char *pSchemeName = getSchemeInfo().m_pScheme;
++ if (pSchemeName[0] != '\0') {
++ aSynScheme = rtl::OUString::createFromAscii(pSchemeName);
+ }
+ m_aScheme.set(aSynAbsURIRef, aSynScheme, aSynAbsURIRef.getLength());
+ aSynAbsURIRef.append(sal_Unicode(':'));
+@@ -2052,6 +2066,8 @@ INetURLObject::getPrefix(sal_Unicode const *& rBegin,
+ PrefixInfo::INTERNAL },
+ { "cid:", 0, INET_PROT_CID, PrefixInfo::OFFICIAL },
+ { "data:", 0, INET_PROT_DATA, PrefixInfo::OFFICIAL },
++ { "dav:", 0, INET_PROT_DAV, PrefixInfo::OFFICIAL },
++ { "davs:", 0, INET_PROT_DAVS, PrefixInfo::OFFICIAL },
+ { "db:", "staroffice.db:", INET_PROT_DB, PrefixInfo::INTERNAL },
+ { "file:", 0, INET_PROT_FILE, PrefixInfo::OFFICIAL },
+ { "ftp:", 0, INET_PROT_FTP, PrefixInfo::OFFICIAL },
+@@ -2133,6 +2149,8 @@ INetURLObject::getPrefix(sal_Unicode const *& rBegin,
+ PrefixInfo::OFFICIAL },
+ { "vnd.sun.star.wfs:", 0, INET_PROT_VND_SUN_STAR_WFS,
+ PrefixInfo::OFFICIAL },
++ { "webdav:", 0, INET_PROT_WEBDAV, PrefixInfo::OFFICIAL },
++ { "webdavs:", 0, INET_PROT_WEBDAVS, PrefixInfo::OFFICIAL },
+ { "wfs:", "vnd.sun.star.wfs:", INET_PROT_VND_SUN_STAR_WFS,
+ PrefixInfo::ALIAS } };
+ PrefixInfo const * pFirst = aMap + 1;
+@@ -2929,6 +2947,10 @@ bool INetURLObject::parsePath(INetProtocol eScheme,
+ case INET_PROT_VND_SUN_STAR_WEBDAV:
+ case INET_PROT_HTTPS:
+ case INET_PROT_SMB:
++ case INET_PROT_DAV:
++ case INET_PROT_DAVS:
++ case INET_PROT_WEBDAV:
++ case INET_PROT_WEBDAVS:
+ if (pPos < pEnd && *pPos != '/')
+ return false;
+ while (pPos < pEnd && *pPos != nQueryDelimiter
+@@ -3343,6 +3365,7 @@ bool INetURLObject::parsePath(INetProtocol eScheme,
+ break;
+
+ case INET_PROT_GENERIC:
++ case INET_PROT_GENERIC_HIERARCHICAL:
+ while (pPos < pEnd && *pPos != nFragmentDelimiter)
+ {
+ EscapeType eEscapeType;
+@@ -4044,10 +4067,13 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme,
+ {
+ setInvalid();
+ m_eScheme = eTheScheme;
+- if (HasError() || m_eScheme == INET_PROT_GENERIC)
++ const char *pSchemeName = getSchemeInfo().m_pScheme;
++
++ if (HasError() || pSchemeName[0] == '\0')
+ return false;
++
+ m_aAbsURIRef.setLength(0);
+- m_aAbsURIRef.appendAscii(getSchemeInfo().m_pScheme);
++ m_aAbsURIRef.appendAscii(pSchemeName);
+ m_aAbsURIRef.append(sal_Unicode(':'));
+ if (getSchemeInfo().m_bAuthority)
+ {
+diff --git tools/workben/urltest.cxx tools/workben/urltest.cxx
+index dd0f964..74380be 100644
+--- tools/workben/urltest.cxx
++++ tools/workben/urltest.cxx
+@@ -1476,7 +1476,7 @@ main()
+
+ url = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("A-b.3:/%2f?x#y"));
+ urlobj = INetURLObject(url);
+- bSuccess &= assertEqual(url, INET_PROT_GENERIC, urlobj.GetProtocol());
++ bSuccess &= assertEqual(url, INET_PROT_GENERIC_HIERARCHICAL, urlobj.GetProtocol());
+ bSuccess &= assertEqual(
+ url, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("a-b.3:/%2F?x#y")),
+ rtl::OUString(urlobj.GetMainURL(INetURLObject::NO_DECODE)));
+@@ -1504,7 +1504,7 @@ main()
+
+ url = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foo:/"));
+ urlobj = INetURLObject(url);
+- bSuccess &= assertEqual(url, INET_PROT_GENERIC, urlobj.GetProtocol());
++ bSuccess &= assertEqual(url, INET_PROT_GENERIC_HIERARCHICAL, urlobj.GetProtocol());
+ bSuccess &= assertEqual(
+ url, url,
+ rtl::OUString(urlobj.GetMainURL(INetURLObject::NO_DECODE)));
+@@ -1542,7 +1542,7 @@ main()
+
+ url = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("A-b.3:/%2f?x#y"));
+ urlobj = INetURLObject(url, INET_PROT_CID);
+- bSuccess &= assertEqual(url, INET_PROT_GENERIC, urlobj.GetProtocol());
++ bSuccess &= assertEqual(url, INET_PROT_GENERIC_HIERARCHICAL, urlobj.GetProtocol());
+ bSuccess &= assertEqual(
+ url, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("a-b.3:/%2F?x#y")),
+ rtl::OUString(urlobj.GetMainURL(INetURLObject::NO_DECODE)));
+@@ -1563,7 +1563,7 @@ main()
+
+ url = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("foo:/"));
+ urlobj = INetURLObject(url, INET_PROT_CID);
+- bSuccess &= assertEqual(url, INET_PROT_GENERIC, urlobj.GetProtocol());
++ bSuccess &= assertEqual(url, INET_PROT_GENERIC_HIERARCHICAL, urlobj.GetProtocol());
+ bSuccess &= assertEqual(
+ url, url,
+ rtl::OUString(urlobj.GetMainURL(INetURLObject::NO_DECODE)));
+diff --git ucb/source/ucp/file/filglob.cxx ucb/source/ucp/file/filglob.cxx
+index b1fc23e..1a89ce0 100644
+--- ucb/source/ucp/file/filglob.cxx
++++ ucb/source/ucp/file/filglob.cxx
+@@ -435,17 +435,13 @@ namespace fileaccess {
+ // not enough memory for allocating structures
+ ioErrorCode = IOErrorCode_OUT_OF_MEMORY;
+ break;
+- case FileBase::E_BUSY:
+- // Text file busy
+- ioErrorCode = IOErrorCode_LOCKING_VIOLATION;
+- break;
+- case FileBase::E_AGAIN:
+- // Operation would block
++
++ case FileBase::E_BUSY: // Text file busy
++ case FileBase::E_AGAIN: // Operation would block
++ case FileBase::E_NOLCK: // No record locks available
++ case FileBase::E_TXTBSY:// Text file busy
+ ioErrorCode = IOErrorCode_LOCKING_VIOLATION;
+ break;
+- case FileBase::E_NOLCK: // No record locks available
+- ioErrorCode = IOErrorCode_LOCKING_VIOLATION;
+- break;
+
+ case FileBase::E_FAULT: // Bad address
+ case FileBase::E_LOOP: // Too many symbolic links encountered
+diff --git ucb/source/ucp/webdav/DAVRequestEnvironment.hxx ucb/source/ucp/webdav/DAVRequestEnvironment.hxx
+index d8cbe52..0cf5c85 100644
+--- ucb/source/ucp/webdav/DAVRequestEnvironment.hxx
++++ ucb/source/ucp/webdav/DAVRequestEnvironment.hxx
+@@ -34,6 +34,10 @@
+ #include <rtl/ref.hxx>
+ #include "DAVAuthListener.hxx"
+
++#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HPP_
++#include <com/sun/star/ucb/XCommandEnvironment.hpp>
++#endif
++
+ namespace webdav_ucp
+ {
+ typedef std::pair< rtl::OUString, rtl::OUString > DAVRequestHeader;
+@@ -46,12 +50,12 @@ struct DAVRequestEnvironment
+ // rtl::Reference< DAVStatusListener > m_xStatusListener;
+ // rtl::Reference< DAVProgressListener > m_xStatusListener;
+ DAVRequestHeaders m_aRequestHeaders;
+- uno::Reference< ucb::XCommandEnvironment > m_xEnv;
++ com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > m_xEnv;
+
+-DAVRequestEnvironment( const rtl::OUString & rRequestURI,
++ DAVRequestEnvironment( const rtl::OUString & rRequestURI,
+ const rtl::Reference< DAVAuthListener > & xListener,
+ const DAVRequestHeaders & rRequestHeaders,
+- const uno::Reference< ucb::XCommandEnvironment > & xEnv)
++ const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > & xEnv)
+ : m_aRequestURI( rRequestURI ),
+ m_xAuthListener( xListener ),
+ m_aRequestHeaders( rRequestHeaders ),
+diff --git ucb/source/ucp/webdav/DAVResourceAccess.cxx ucb/source/ucp/webdav/DAVResourceAccess.cxx
+index 75e0b64..0d4ce5a 100644
+--- ucb/source/ucp/webdav/DAVResourceAccess.cxx
++++ ucb/source/ucp/webdav/DAVResourceAccess.cxx
+@@ -42,6 +42,13 @@
+ #include "DAVAuthListenerImpl.hxx"
+ #include "DAVResourceAccess.hxx"
+
++#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
++#include <comphelper/processfactory.hxx>
++#endif
++#ifndef _UCBHELPER_COMMANDENVIRONMENT_HXX
++#include <ucbhelper/commandenvironment.hxx>
++#endif
++
+ using namespace webdav_ucp;
+ using namespace com::sun::star;
+
+@@ -61,56 +68,55 @@ int DAVAuthListener_Impl::authenticate(
+ ::rtl::OUString & inoutUserName,
+ ::rtl::OUString & outPassWord )
+ {
++ uno::Reference< task::XInteractionHandler > xIH;
++
+ if ( m_xEnv.is() )
+- {
+- uno::Reference< task::XInteractionHandler > xIH
+- = m_xEnv->getInteractionHandler();
+- if ( xIH.is() )
+- {
+- // #102871# - Supply username and password from previous try.
+- // Password container service depends on this!
+- if ( inoutUserName.getLength() == 0 )
+- inoutUserName = m_aPrevUsername;
+-
+- if ( outPassWord.getLength() == 0 )
+- outPassWord = m_aPrevPassword;
+-
+- rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
+- = new ucbhelper::SimpleAuthenticationRequest( inHostName,
+- inRealm,
+- inoutUserName,
+- outPassWord );
+- xIH->handle( xRequest.get() );
+-
+- rtl::Reference< ucbhelper::InteractionContinuation > xSelection
+- = xRequest->getSelection();
+-
+- if ( xSelection.is() )
+- {
+- // Handler handled the request.
+- uno::Reference< task::XInteractionAbort > xAbort(
+- xSelection.get(), uno::UNO_QUERY );
+- if ( !xAbort.is() )
+- {
+- const rtl::Reference<
+- ucbhelper::InteractionSupplyAuthentication > & xSupp
+- = xRequest->getAuthenticationSupplier();
+-
+- inoutUserName = xSupp->getUserName();
+- outPassWord = xSupp->getPassword();
+-
+- // #102871# - Remember username and password.
+- m_aPrevUsername = inoutUserName;
+- m_aPrevPassword = outPassWord;
+-
+- // go on.
+- return 0;
+- }
+- }
+- }
+- }
+- // Abort.
+- return -1;
++ xIH = m_xEnv->getInteractionHandler();
++ else
++ xIH = DAVResourceAccess::createCommandEnvironment()->getInteractionHandler();
++
++ if ( !xIH.is() )
++ return -1;
++
++ // #102871# - Supply username and password from previous try.
++ // Password container service depends on this!
++ if ( inoutUserName.getLength() == 0 )
++ inoutUserName = m_aPrevUsername;
++
++ if ( outPassWord.getLength() == 0 )
++ outPassWord = m_aPrevPassword;
++
++ rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
++ = new ucbhelper::SimpleAuthenticationRequest( inHostName,
++ inRealm,
++ inoutUserName,
++ outPassWord );
++ xIH->handle( xRequest.get() );
++
++ rtl::Reference< ucbhelper::InteractionContinuation > xSelection
++ = xRequest->getSelection();
++
++ if ( !xSelection.is() )
++ return -1;
++
++ // Handler handled the request.
++ uno::Reference< task::XInteractionAbort > xAbort(
++ xSelection.get(), uno::UNO_QUERY );
++ if ( xAbort.is() )
++ return -1;
++
++ const rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp
++ = xRequest->getAuthenticationSupplier();
++
++ inoutUserName = xSupp->getUserName();
++ outPassWord = xSupp->getPassword();
++
++ // #102871# - Remember username and password.
++ m_aPrevUsername = inoutUserName;
++ m_aPrevPassword = outPassWord;
++
++ // go on.
++ return 0;
+ }
+
+ //=========================================================================
+@@ -444,15 +450,16 @@ void DAVResourceAccess::GET(
+ }
+
+ //=========================================================================
+-uno::Reference< io::XInputStream > DAVResourceAccess::GET(
++uno::Reference< io::XStream > DAVResourceAccess::GET(
+ const std::vector< rtl::OUString > & rHeaderNames,
+ DAVResource & rResource,
+- const uno::Reference< ucb::XCommandEnvironment > & xEnv )
++ const uno::Reference< ucb::XCommandEnvironment > & xEnv,
++ sal_Bool bAllowEmpty )
+ throw( DAVException )
+ {
+ initialize();
+
+- uno::Reference< io::XInputStream > xStream;
++ uno::Reference< io::XStream > xStream;
+ int errorCount = 0;
+ bool bRetry;
+ do
+@@ -472,7 +479,8 @@ uno::Reference< io::XInputStream > DAVResourceAccess::GET(
+ DAVRequestEnvironment(
+ getRequestURI(),
+ new DAVAuthListener_Impl( xEnv ),
+- aHeaders, xEnv ) );
++ aHeaders, xEnv ),
++ bAllowEmpty );
+ }
+ catch ( DAVException & e )
+ {
+@@ -606,6 +614,45 @@ void DAVResourceAccess::PUT(
+ }
+
+ //=========================================================================
++void DAVResourceAccess::PUT(
++ const char * buffer, size_t size,
++ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
++throw( DAVException )
++{
++ initialize();
++
++ bool bRetry = false;
++ int errorCount = 0;
++ do
++ {
++ bRetry = false;
++ try
++ {
++ DAVRequestHeaders aHeaders;
++ getUserRequestHeaders( xEnv,
++ getRequestURI(),
++ rtl::OUString::createFromAscii( "PUT" ),
++ aHeaders );
++
++ m_xSession->PUT( getRequestURI(),
++ buffer, size,
++ DAVRequestEnvironment(
++ getRequestURI(),
++ new DAVAuthListener_Impl( xEnv ),
++ aHeaders, xEnv ) );
++ }
++ catch ( DAVException & e )
++ {
++ errorCount++;
++ bRetry = handleException( e, errorCount );
++ if ( !bRetry )
++ throw;
++ }
++ }
++ while ( bRetry );
++}
++
++//=========================================================================
+ uno::Reference< io::XInputStream > DAVResourceAccess::POST(
+ const rtl::OUString & rContentType,
+ const rtl::OUString & rReferer,
+@@ -888,22 +935,44 @@ void DAVResourceAccess::DESTROY(
+
+ //=========================================================================
+ void DAVResourceAccess::LOCK (
+- const ucb::Lock & /*rLock*/,
+- const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
++ ucb::Lock & rLock,
++ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException )
+ {
+-// initialize();
+- OSL_ENSURE( sal_False, "DAVResourceAccess::LOCK - NYI" );
++ initialize();
++
++ DAVRequestHeaders aHeaders;
++ getUserRequestHeaders( xEnv,
++ getRequestURI(),
++ rtl::OUString::createFromAscii( "LOCK" ),
++ aHeaders );
++
++ m_xSession->LOCK( rLock,
++ DAVRequestEnvironment(
++ getRequestURI(),
++ new DAVAuthListener_Impl( xEnv ),
++ aHeaders, xEnv ) );
+ }
+
+ //=========================================================================
+ void DAVResourceAccess::UNLOCK (
+- const ucb::Lock & /*rLock*/,
+- const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
++ ucb::Lock & rLock,
++ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException )
+ {
+-// initialize();
+- OSL_ENSURE( sal_False, "DAVResourceAccess::UNLOCK - NYI" );
++ initialize();
++
++ DAVRequestHeaders aHeaders;
++ getUserRequestHeaders( xEnv,
++ getRequestURI(),
++ rtl::OUString::createFromAscii( "UNLOCK" ),
++ aHeaders );
++
++ m_xSession->UNLOCK( rLock,
++ DAVRequestEnvironment(
++ getRequestURI(),
++ new DAVAuthListener_Impl( xEnv ),
++ aHeaders, xEnv ) );
+ }
+
+ //=========================================================================
+@@ -1008,6 +1077,18 @@ void DAVResourceAccess::getUserRequestHeaders(
+ }
+ }
+
++// static
++com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > DAVResourceAccess::createCommandEnvironment( void )
++{
++ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
++ uno::Reference< task::XInteractionHandler > xInteractionHandler = uno::Reference< task::XInteractionHandler > (
++ xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), uno::UNO_QUERY );
++ ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, uno::Reference< ucb::XProgressHandler >() );
++
++ return uno::Reference< ucb::XCommandEnvironment >( static_cast< ucb::XCommandEnvironment* >( pCommandEnv ), uno::UNO_QUERY );
++}
++
++
+ //=========================================================================
+ sal_Bool DAVResourceAccess::detectRedirectCycle(
+ const rtl::OUString& rRedirectURL )
+diff --git ucb/source/ucp/webdav/DAVResourceAccess.hxx ucb/source/ucp/webdav/DAVResourceAccess.hxx
+index ca6a188..b1a1d15 100644
+--- ucb/source/ucp/webdav/DAVResourceAccess.hxx
++++ ucb/source/ucp/webdav/DAVResourceAccess.hxx
+@@ -134,11 +134,12 @@ public:
+ com::sun::star::ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException );
+
+- com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
++ com::sun::star::uno::Reference< com::sun::star::io::XStream >
+ GET( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
+ DAVResource & rResource,
+ const com::sun::star::uno::Reference<
+- com::sun::star::ucb::XCommandEnvironment > & xEnv )
++ com::sun::star::ucb::XCommandEnvironment > & xEnv,
++ sal_Bool bAllowEmpty = sal_False )
+ throw( DAVException );
+
+ void
+@@ -157,6 +158,11 @@ public:
+ com::sun::star::ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException );
+
++ void
++ PUT( const char * buffer, size_t size,
++ const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > & xEnv )
++ throw( DAVException );
++
+ com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
+ POST( const rtl::OUString & rContentType,
+ const rtl::OUString & rReferer,
+@@ -204,13 +210,13 @@ public:
+ throw( DAVException );
+
+ void
+- LOCK( const com::sun::star::ucb::Lock & rLock,
++ LOCK( com::sun::star::ucb::Lock & rLock,
+ const com::sun::star::uno::Reference<
+ com::sun::star::ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException );
+
+ void
+- UNLOCK( const com::sun::star::ucb::Lock & rLock,
++ UNLOCK( com::sun::star::ucb::Lock & rLock,
+ const com::sun::star::uno::Reference<
+ com::sun::star::ucb::XCommandEnvironment > & xEnv )
+ throw( DAVException );
+@@ -223,6 +229,8 @@ public:
+ const rtl::OUString & rMethod,
+ DAVRequestHeaders & rRequestHeaders );
+
++ static com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > createCommandEnvironment( void );
++
+ private:
+ const rtl::OUString & getRequestURI() const;
+ sal_Bool detectRedirectCycle( const rtl::OUString& rRedirectURL )
+diff --git ucb/source/ucp/webdav/DAVSession.hxx ucb/source/ucp/webdav/DAVSession.hxx
+index 8f055ab..9a675cb 100644
+--- ucb/source/ucp/webdav/DAVSession.hxx
++++ ucb/source/ucp/webdav/DAVSession.hxx
+@@ -33,8 +33,11 @@
+
+ #include <memory>
+ #include <rtl/ustring.hxx>
++#include <com/sun/star/io/XStream.hpp>
+ #include <com/sun/star/io/XInputStream.hpp>
+ #include <com/sun/star/io/XOutputStream.hpp>
++#include <com/sun/star/ucb/Lock.hpp>
++
+ #include "DAVException.hxx"
+ #include "DAVProperties.hxx"
+ #include "DAVResource.hxx"
+@@ -42,8 +45,6 @@
+ #include "DAVTypes.hxx"
+ #include "DAVRequestEnvironment.hxx"
+
+-
+-
+ namespace webdav_ucp
+ {
+
+@@ -114,11 +115,12 @@ public:
+ const DAVRequestEnvironment & rEnv )
+ throw( DAVException ) = 0;
+
+- virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
++ virtual com::sun::star::uno::Reference< com::sun::star::io::XStream >
+ GET( const ::rtl::OUString & inPath,
+ const std::vector< ::rtl::OUString > & inHeaderNames,
+ DAVResource & ioResource,
+- const DAVRequestEnvironment & rEnv )
++ const DAVRequestEnvironment & rEnv,
++ sal_Bool bAllowEmpty )
+ throw( DAVException ) = 0;
+
+ virtual void GET( const ::rtl::OUString & inPath,
+@@ -134,6 +136,12 @@ public:
+ const DAVRequestEnvironment & rEnv )
+ throw( DAVException ) = 0;
+
++ virtual void PUT( const ::rtl::OUString & inPath,
++ const char * buffer,
++ size_t size,
++ const DAVRequestEnvironment & rEnv )
++ throw ( DAVException ) = 0;
++
+ virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
+ POST( const rtl::OUString & inPath,
+ const rtl::OUString & rContentType,
+@@ -173,16 +181,14 @@ public:
+ const DAVRequestEnvironment & rEnv )
+ throw( DAVException ) = 0;
+
+- // Note: Uncomment the following if locking support is required
+- /*
+- virtual void LOCK ( const Lock & inLock,
++ virtual void LOCK ( com::sun::star::ucb::Lock & rLock,
+ const DAVRequestEnvironment & rEnv )
+ throw( DAVException ) = 0;
+
+- virtual void UNLOCK ( const Lock & inLock,
++ virtual void UNLOCK ( com::sun::star::ucb::Lock & rLock,
+ const DAVRequestEnvironment & rEnv )
+ throw( DAVException ) = 0;
+- */
++
+ protected:
+ rtl::Reference< DAVSessionFactory > m_xFactory;
+
+diff --git ucb/source/ucp/webdav/NeonInputStream.cxx ucb/source/ucp/webdav/NeonInputStream.cxx
+index 581b284..3a97992 100644
+--- ucb/source/ucp/webdav/NeonInputStream.cxx
++++ ucb/source/ucp/webdav/NeonInputStream.cxx
+@@ -31,22 +31,146 @@
+ // MARKER(update_precomp.py): autogen include statement, do not remove
+ #include "precompiled_ucb.hxx"
+ #include "NeonInputStream.hxx"
++#include "DAVResourceAccess.hxx"
++
+ #include <rtl/memory.h>
++#include <osl/thread.hxx>
++#include <com/sun/star/ucb/CommandFailedException.hpp>
++
++#include <comphelper/processfactory.hxx>
++#include <com/sun/star/lang/XMultiServiceFactory.hpp>
++
++#include <cstdio>
+
+ using namespace cppu;
+-using namespace rtl;
+ using namespace com::sun::star::io;
+-using namespace com::sun::star::uno;
++using namespace com::sun::star;
+ using namespace webdav_ucp;
+
++// Our signal - 246 is just a random number ;-)
++#define TICKER_THREAD_USER_SIGNAL ( OSL_SIGNAL_USER_RESERVED + 246 )
++
++// -------------------------------------------------------------------
++// A thread that 'ticks' - emits the user signal every second
++// -------------------------------------------------------------------
++class TickerThread : public osl::Thread
++{
++ bool m_bFinish;
++
++public:
++
++ TickerThread() : osl::Thread(), m_bFinish( false ) {}
++
++ void finish() { m_bFinish = true; }
++
++protected:
++
++ virtual void SAL_CALL run();
++};
++
++void TickerThread::run()
++{
++ // we have to go through the loop more often to be able to finish ~quickly
++ const int nNth = 25;
++
++ int nCount = nNth;
++ while ( !m_bFinish )
++ {
++ if ( nCount-- <= 0 )
++ {
++ osl_raiseSignal( TICKER_THREAD_USER_SIGNAL, NULL );
++ nCount = nNth;
++ }
++
++ TimeValue aTV;
++ aTV.Seconds = 0;
++ aTV.Nanosec = 1000000000/nNth;
++ wait( aTV );
++ }
++}
++
++// -------------------------------------------------------------------
++// A class that takes care of creating and destroying the ticker thread
++// -------------------------------------------------------------------
++class TickerThreadController
++{
++ osl::Mutex m_aMutex;
++ int m_nCount;
++ TickerThread *m_pTickerThread;
++
++public:
++
++ TickerThreadController() : m_nCount( 0 ), m_pTickerThread( NULL ) {}
++
++ void start();
++ void stop();
++};
++
++void TickerThreadController::start()
++{
++ osl::MutexGuard aGuard( m_aMutex );
++
++ if ( ( m_nCount++ == 0 ) && !m_pTickerThread )
++ {
++ m_pTickerThread = new TickerThread();
++ m_pTickerThread->create();
++ }
++}
++
++void TickerThreadController::stop()
++{
++ osl::MutexGuard aGuard( m_aMutex );
++
++ if ( ( --m_nCount == 0 ) && m_pTickerThread )
++ {
++ m_pTickerThread->finish();
++ m_pTickerThread->join();
++
++ delete m_pTickerThread;
++ m_pTickerThread = NULL;
++ }
++}
++
++// -------------------------------------------------------------------
++// Signal handler
++// -------------------------------------------------------------------
++oslSignalAction NeonInputStream::HandleLockingSignal( void* pData, oslSignalInfo* pSignalInfo )
++{
++ NeonInputStream *pStream = static_cast< NeonInputStream *>( pData );
++
++ if ( !pStream )
++ return osl_Signal_ActCallNextHdl;
++
++ if ( pSignalInfo &&
++ pSignalInfo->Signal == osl_Signal_User &&
++ pSignalInfo->UserSignal == TICKER_THREAD_USER_SIGNAL )
++ {
++ pStream->RefreshLock();
++ }
++ else if ( !pSignalInfo || ( pSignalInfo->Signal != osl_Signal_User ) )
++ {
++ // terminating or something, let's unlock the stream
++ pStream->Unlock();
++ }
++
++ return osl_Signal_ActCallNextHdl;
++}
++
++static TickerThreadController sTickerThreadController;
+
+ // -------------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------------
+-NeonInputStream::NeonInputStream( void )
+-: mLen( 0 ),
+- mPos( 0 )
++NeonInputStream::NeonInputStream()
++: m_nLen( 0 ),
++ m_nPos( 0 ),
++ m_bDirty( sal_False ),
++ m_pLock( NULL ),
++ m_nToExpire( -1 )
+ {
++ m_pSignalHandler = osl_addSignalHandler( NeonInputStream::HandleLockingSignal, this );
++
++ sTickerThreadController.start();
+ }
+
+ // -------------------------------------------------------------------
+@@ -54,6 +178,11 @@ NeonInputStream::NeonInputStream( void )
+ // -------------------------------------------------------------------
+ NeonInputStream::~NeonInputStream( void )
+ {
++ sTickerThreadController.stop();
++
++ Unlock();
++
++ osl_removeSignalHandler( m_pSignalHandler );
+ }
+
+ // -------------------------------------------------------------------
+@@ -62,24 +191,68 @@ NeonInputStream::~NeonInputStream( void )
+ // -------------------------------------------------------------------
+ void NeonInputStream::AddToStream( const char * inBuf, sal_Int32 inLen )
+ {
+- mInputBuffer.realloc( sal::static_int_cast<sal_Int32>(mLen) + inLen );
+- rtl_copyMemory( mInputBuffer.getArray() + mLen, inBuf, inLen );
+- mLen += inLen;
++ OSL_ENSURE( !m_bDirty, "Cannot AddToStream() when it was already written to it." );
++
++ m_aInputBuffer.realloc( sal::static_int_cast<sal_Int32>(m_nLen) + inLen );
++ rtl_copyMemory( m_aInputBuffer.getArray() + m_nLen, inBuf, inLen );
++ m_nLen += inLen;
++}
++
++// -------------------------------------------------------------------
++// Associate a lock with this stream
++// -------------------------------------------------------------------
++void NeonInputStream::SetLock( const com::sun::star::ucb::Lock &rLock,
++ const rtl::OUString &rURL )
++{
++ osl::MutexGuard aGuard( m_aLock );
++
++ m_aURL = rURL;
++
++ if ( !m_pLock )
++ m_pLock = new ucb::Lock( rLock );
++ else
++ *m_pLock = rLock;
++
++ if ( m_pLock )
++ m_nToExpire = m_pLock->Timeout;
+ }
+
+ // -------------------------------------------------------------------
+ // queryInterface
+ // -------------------------------------------------------------------
+-Any NeonInputStream::queryInterface( const Type &type )
+- throw( RuntimeException )
++uno::Any NeonInputStream::queryInterface( const uno::Type &type )
++ throw( uno::RuntimeException )
+ {
+- Any aRet = ::cppu::queryInterface( type,
+- static_cast< XInputStream * >( this ),
+- static_cast< XSeekable * >( this ) );
++ uno::Any aRet = ::cppu::queryInterface( type,
++ static_cast< XStream * >( this ),
++ static_cast< XInputStream * >( this ),
++ static_cast< XOutputStream * >( this ),
++ static_cast< XSeekable * >( this ),
++ static_cast< XTruncate * >( this ) );
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( type );
+ }
+
+ // -------------------------------------------------------------------
++// getInputStream
++// -------------------------------------------------------------------
++com::sun::star::uno::Reference< com::sun::star::io::XInputStream > SAL_CALL
++NeonInputStream::getInputStream( void )
++ throw( com::sun::star::uno::RuntimeException )
++{
++ return uno::Reference< XInputStream >( this );
++}
++
++// -------------------------------------------------------------------
++// getOutputStream
++// -------------------------------------------------------------------
++com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > SAL_CALL
++NeonInputStream::getOutputStream( void )
++ throw( com::sun::star::uno::RuntimeException )
++{
++ return uno::Reference< XOutputStream >( this );
++}
++
++// -------------------------------------------------------------------
+ // readBytes
+ // "Reads" the specified number of bytes from the stream
+ // -------------------------------------------------------------------
+@@ -92,7 +265,7 @@ sal_Int32 SAL_CALL NeonInputStream::readBytes(
+ {
+ // Work out how much we're actually going to write
+ sal_Int32 theBytes2Read = nBytesToRead;
+- sal_Int32 theBytesLeft = sal::static_int_cast<sal_Int32>(mLen - mPos);
++ sal_Int32 theBytesLeft = sal::static_int_cast<sal_Int32>(m_nLen - m_nPos);
+ if ( theBytes2Read > theBytesLeft )
+ theBytes2Read = theBytesLeft;
+
+@@ -101,10 +274,10 @@ sal_Int32 SAL_CALL NeonInputStream::readBytes(
+
+ // Write the data
+ rtl_copyMemory(
+- aData.getArray(), mInputBuffer.getConstArray() + mPos, theBytes2Read );
++ aData.getArray(), m_aInputBuffer.getConstArray() + m_nPos, theBytes2Read );
+
+ // Update our stream position for next time
+- mPos += theBytes2Read;
++ m_nPos += theBytes2Read;
+
+ return theBytes2Read;
+ }
+@@ -133,9 +306,9 @@ void SAL_CALL NeonInputStream::skipBytes( sal_Int32 nBytesToSkip )
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException )
+ {
+- mPos += nBytesToSkip;
+- if ( mPos >= mLen )
+- mPos = mLen;
++ m_nPos += nBytesToSkip;
++ if ( m_nPos >= m_nLen )
++ m_nPos = m_nLen;
+ }
+
+ // -------------------------------------------------------------------
+@@ -147,7 +320,7 @@ sal_Int32 SAL_CALL NeonInputStream::available( )
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException )
+ {
+- return sal::static_int_cast<sal_Int32>(mLen - mPos);
++ return sal::static_int_cast<sal_Int32>(m_nLen - m_nPos);
+ }
+
+ // -------------------------------------------------------------------
+@@ -168,12 +341,12 @@ void SAL_CALL NeonInputStream::seek( sal_Int64 location )
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException )
+ {
+- if ( location < 0 )
+- throw ::com::sun::star::lang::IllegalArgumentException();
++ if ( location < 0 )
++ throw ::com::sun::star::lang::IllegalArgumentException();
+
+- if ( location <= mLen )
+- mPos = location;
+- else
++ if ( location <= m_nLen )
++ m_nPos = location;
++ else
+ throw ::com::sun::star::lang::IllegalArgumentException();
+ }
+
+@@ -184,7 +357,7 @@ sal_Int64 SAL_CALL NeonInputStream::getPosition()
+ throw( ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException )
+ {
+- return mPos;
++ return m_nPos;
+ }
+
+ // -------------------------------------------------------------------
+@@ -194,5 +367,168 @@ sal_Int64 SAL_CALL NeonInputStream::getLength()
+ throw( ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException )
+ {
+- return mLen;
++ return m_nLen;
++}
++
++// -------------------------------------------------------------------
++// writeBytes
++// -------------------------------------------------------------------
++void SAL_CALL NeonInputStream::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData )
++ throw( com::sun::star::io::NotConnectedException,
++ com::sun::star::io::BufferSizeExceededException,
++ com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException)
++{
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: writeBytes()\n" );
++#endif
++
++ sal_Int32 nDataLen = aData.getLength();
++ OSL_ASSERT( nDataLen >= 0 );
++
++ // Anything to do?
++ if ( nDataLen == 0 )
++ return;
++
++ // Update the length of the stream & size of the buffer
++ if ( m_nLen < m_nPos + nDataLen )
++ {
++ m_nLen = m_nPos + nDataLen;
++ if ( m_aInputBuffer.getLength() < m_nLen )
++ m_aInputBuffer.realloc( sal::static_int_cast<sal_Int32>( m_nLen ) );
++ }
++
++ rtl_copyMemory( m_aInputBuffer.getArray() + m_nPos, aData.getConstArray(), nDataLen );
++ m_nPos += nDataLen;
++
++ m_bDirty = sal_True;
++}
++
++// -------------------------------------------------------------------
++// flush
++// -------------------------------------------------------------------
++void SAL_CALL NeonInputStream::flush( void )
++ throw( NotConnectedException, BufferSizeExceededException,
++ IOException, uno::RuntimeException )
++{
++ if ( m_bDirty )
++ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: flush(), saving the changed file.\n" );
++#endif
++ // FIXME It's really hacky to create the new session
++ // But so far it seems I have no other chance...
++ // see also NeonInputStream::Unlock()
++ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
++ rtl::Reference< DAVSessionFactory > rDAVFactory( new DAVSessionFactory() );
++
++ DAVResourceAccess aResourceAccess( xFactory, rDAVFactory, m_aURL );
++
++ try {
++ aResourceAccess.PUT( reinterpret_cast<const char*>( m_aInputBuffer.getConstArray() ), m_nLen,
++ DAVResourceAccess::createCommandEnvironment() );
++ }
++ catch ( DAVException & e )
++ {
++ throw ucb::CommandFailedException(
++ e.getData(),
++ uno::Reference< uno::XInterface >(),
++ uno::makeAny( e.getData() ) );
++ }
++
++ m_bDirty = sal_False;
++ }
++}
++
++// -------------------------------------------------------------------
++// closeOutput
++// -------------------------------------------------------------------
++void SAL_CALL NeonInputStream::closeOutput( void )
++ throw( com::sun::star::io::NotConnectedException,
++ com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException )
++{
++ if ( m_bDirty )
++ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: TODO write on closeOutput(), the stream is dirty!\n" );
++#endif
++ }
++}
++
++// -------------------------------------------------------------------
++// truncate
++// -------------------------------------------------------------------
++void SAL_CALL NeonInputStream::truncate( void )
++ throw( com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException )
++{
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: truncate()\n" );
++#endif
++
++ if ( m_nLen > 0 )
++ {
++ m_nLen = m_nPos = 0;
++ m_bDirty = sal_True;
++ }
++}
++
++// -------------------------------------------------------------------
++// Lock the stream again
++// -------------------------------------------------------------------
++void NeonInputStream::RefreshLock( void )
++{
++ osl::MutexGuard aGuard( m_aLock );
++
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: RefreshLock() - will refresh in %d sec\n", m_nToExpire - 30 );
++#endif
++
++ if ( m_nToExpire > 0 )
++ --m_nToExpire;
++
++ // Refresh the lock if it expires in less than 30 sec
++ if ( m_pLock && m_nToExpire >= 0 && m_nToExpire < 30 )
++ {
++ // FIXME It's really hacky to create the new session
++ // But so far it seems I have no other chance...
++ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
++ rtl::Reference< DAVSessionFactory > rDAVFactory( new DAVSessionFactory() );
++
++ DAVResourceAccess aResourceAccess( xFactory, rDAVFactory, m_aURL );
++
++ aResourceAccess.LOCK( *m_pLock, DAVResourceAccess::createCommandEnvironment() );
++
++ m_nToExpire = m_pLock->Timeout;
++ }
++}
++
++// -------------------------------------------------------------------
++// Unlock the stream & destroy the lock
++// -------------------------------------------------------------------
++void NeonInputStream::Unlock( void )
++{
++ osl::MutexGuard aGuard( m_aLock );
++
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: unlock()\n" );
++#endif
++
++ if ( m_pLock )
++ {
++ // FIXME It's really hacky to create the new session
++ // But so far it seems I have no other chance...
++ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
++ rtl::Reference< DAVSessionFactory > rDAVFactory( new DAVSessionFactory() );
++
++ DAVResourceAccess aResourceAccess( xFactory, rDAVFactory, m_aURL );
++
++ aResourceAccess.UNLOCK( *m_pLock, DAVResourceAccess::createCommandEnvironment() );
++
++ delete m_pLock;
++ m_pLock = NULL;
++
++ m_nToExpire = -1;
++ }
+ }
+diff --git ucb/source/ucp/webdav/NeonInputStream.hxx ucb/source/ucp/webdav/NeonInputStream.hxx
+index 2d83577..8f648e7 100644
+--- ucb/source/ucp/webdav/NeonInputStream.hxx
++++ ucb/source/ucp/webdav/NeonInputStream.hxx
+@@ -31,11 +31,19 @@
+ #define _NEONINPUTSTREAM_HXX_
+
+ #include <sal/types.h>
++#include <osl/mutex.hxx>
++#include <osl/signal.h>
+ #include <rtl/ustring.hxx>
+ #include <cppuhelper/weak.hxx>
++
++#include <com/sun/star/io/XStream.hpp>
+ #include <com/sun/star/io/XInputStream.hpp>
++#include <com/sun/star/io/XOutputStream.hpp>
+ #include <com/sun/star/io/XSeekable.hpp>
++#include <com/sun/star/io/XTruncate.hpp>
++#include <com/sun/star/ucb/Lock.hpp>
+
++#include "DAVRequestEnvironment.hxx"
+
+ namespace webdav_ucp
+ {
+@@ -45,21 +53,38 @@ namespace webdav_ucp
+ // A simple XInputStream implementation provided specifically for use
+ // by the DAVSession::GET method.
+ // -------------------------------------------------------------------
+-class NeonInputStream : public ::com::sun::star::io::XInputStream,
++class NeonInputStream : public ::com::sun::star::io::XStream,
++ public ::com::sun::star::io::XInputStream,
++ public ::com::sun::star::io::XOutputStream,
+ public ::com::sun::star::io::XSeekable,
++ public ::com::sun::star::io::XTruncate,
+ public ::cppu::OWeakObject
+ {
+- private:
+- com::sun::star::uno::Sequence< sal_Int8 > mInputBuffer;
+- sal_Int64 mLen;
+- sal_Int64 mPos;
++private:
++ com::sun::star::uno::Sequence< sal_Int8 > m_aInputBuffer;
++ sal_Int64 m_nLen; // cannot be just m_aInputBuffer.getLength() - the buffer can be bigger
++ sal_Int64 m_nPos;
++
++ sal_Bool m_bDirty;
++
++ com::sun::star::ucb::Lock *m_pLock;
++ int m_nToExpire;
++ rtl::OUString m_aURL;
++
++ oslSignalHandler m_pSignalHandler;
+
+- public:
+- NeonInputStream( void );
+- virtual ~NeonInputStream();
++ osl::Mutex m_aLock;
+
+- // Add some data to the end of the stream
+- void AddToStream( const char * inBuf, sal_Int32 inLen );
++public:
++ NeonInputStream( void );
++ virtual ~NeonInputStream();
++
++ // Add some data to the end of the stream
++ void AddToStream( const char * inBuf, sal_Int32 inLen );
++
++ // Associate a lock with this stream
++ void SetLock( const com::sun::star::ucb::Lock &rLock,
++ const rtl::OUString &rURL );
+
+ // XInterface
+ virtual com::sun::star::uno::Any SAL_CALL queryInterface(
+@@ -74,6 +99,12 @@ class NeonInputStream : public ::com::sun::star::io::XInputStream,
+ throw()
+ { OWeakObject::release(); }
+
++ // XStream
++ virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > SAL_CALL getInputStream( void )
++ throw( com::sun::star::uno::RuntimeException );
++
++ virtual com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( void )
++ throw( com::sun::star::uno::RuntimeException );
+
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes(
+@@ -121,6 +152,42 @@ class NeonInputStream : public ::com::sun::star::io::XInputStream,
+ virtual sal_Int64 SAL_CALL getLength()
+ throw( ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException );
++
++ // XOutputStream
++ virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData )
++ throw( com::sun::star::io::NotConnectedException,
++ com::sun::star::io::BufferSizeExceededException,
++ com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException);
++
++ virtual void SAL_CALL flush( void )
++ throw( com::sun::star::io::NotConnectedException,
++ com::sun::star::io::BufferSizeExceededException,
++ com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException);
++
++
++ virtual void SAL_CALL closeOutput( void )
++ throw( com::sun::star::io::NotConnectedException,
++ com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException );
++
++ // XTruncate
++ virtual void SAL_CALL truncate( void )
++ throw( com::sun::star::io::IOException,
++ com::sun::star::uno::RuntimeException );
++
++protected:
++
++ // Refresh the lock on the stream
++ void RefreshLock( void );
++
++ // Unlock the stream & destroy the lock
++ void Unlock( void );
++
++ // Refresh the lock if necessary, or unlock the stream when
++ // OOo crashes/is terminated/...
++ static oslSignalAction HandleLockingSignal( void* pData, oslSignalInfo* pInfo );
+ };
+
+ } // namespace webdav_ucp
+diff --git ucb/source/ucp/webdav/NeonSession.cxx ucb/source/ucp/webdav/NeonSession.cxx
+index 244ffaa..2daaddd 100644
+--- ucb/source/ucp/webdav/NeonSession.cxx
++++ ucb/source/ucp/webdav/NeonSession.cxx
+@@ -65,6 +65,9 @@
+ #ifndef _SIMPLECERTIFICATIONVALIDATIONREQUEST_HXX_
+ #include "ucbhelper/simplecertificatevalidationrequest.hxx"
+ #endif
++#ifndef _UCBHELPER_CANCELCOMMANDEXECUTION_HXX_
++#include <ucbhelper/cancelcommandexecution.hxx>
++#endif
+
+ #include <cppuhelper/bootstrap.hxx>
+
+@@ -153,6 +156,12 @@ static sal_uInt16 makeStatusCode( const rtl::OUString & rStatusText )
+ return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() );
+ }
+
++static sal_uInt16 getStatusCode( HttpSession *pSession )
++{
++ rtl::OUString aText = rtl::OUString::createFromAscii( ne_get_error( pSession ) );
++ return makeStatusCode( aText );
++}
++
+ // -------------------------------------------------------------------
+ struct NeonRequestContext
+ {
+@@ -196,12 +205,13 @@ struct NeonRequestContext
+ // -------------------------------------------------------------------
+
+ #if NEON_VERSION >= 0x0250
+-extern "C" int NeonSession_ResponseBlockReader(void * inUserData,
++extern "C" int
+ #else
+-extern "C" void NeonSession_ResponseBlockReader(void * inUserData,
++extern "C" void
+ #endif
+- const char * inBuf,
+- size_t inLen )
++NeonSession_ResponseBlockReader( void * inUserData,
++ const char * inBuf,
++ size_t inLen )
+ {
+ // neon calls this function with (inLen == 0)...
+ if ( inLen > 0 )
+@@ -226,12 +236,13 @@ extern "C" void NeonSession_ResponseBlockReader(void * inUserData,
+ // -------------------------------------------------------------------
+
+ #if NEON_VERSION >= 0x0250
+-extern "C" int NeonSession_ResponseBlockWriter( void * inUserData,
++extern "C" int
+ #else
+-extern "C" void NeonSession_ResponseBlockWriter( void * inUserData,
++extern "C" void
+ #endif
+- const char * inBuf,
+- size_t inLen )
++NeonSession_ResponseBlockWriter( void * inUserData,
++ const char * inBuf,
++ size_t inLen )
+ {
+ // neon calls this function with (inLen == 0)...
+ if ( inLen > 0 )
+@@ -297,11 +308,10 @@ extern "C" int NeonSession_NeonAuth( void * inUserData,
+
+ try
+ {
+- NeonUri uri( theSession->getRequestEnvironment().m_aRequestURI );
+- rtl::OUString aUserInfo( uri.GetUserInfo() );
++ rtl::OUString aUserInfo( theSession->getUserInfo() );
+ if ( aUserInfo.getLength() )
+ {
+- sal_Int32 nPos = aUserInfo.indexOf( '@' );
++ sal_Int32 nPos = aUserInfo.indexOf( ':' );
+ if ( nPos == -1 )
+ {
+ theUserName = aUserInfo;
+@@ -561,6 +571,8 @@ extern "C" void NeonSession_PreSendRequest( ne_request * req,
+ }
+ }
+
++NeonLockStore * NeonSession::s_aNeonLockStore = NULL;
++
+ // -------------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------------
+@@ -578,6 +590,7 @@ NeonSession::NeonSession(
+ m_aScheme = theUri.GetScheme();
+ m_aHostName = theUri.GetHost();
+ m_nPort = theUri.GetPort();
++ m_aUserInfo = theUri.GetUserInfo();
+
+ // Init();
+ }
+@@ -591,14 +604,6 @@ NeonSession::~NeonSession( )
+ {
+ ne_session_destroy( m_pHttpSession );
+ m_pHttpSession = 0;
+- // Note: Uncomment the following if locking support is required
+- /*
+- if ( mNeonLockSession != NULL )
+- {
+- ne_lock_unregister( mNeonLockSession );
+- mNeonLockSession = NULL;
+- }
+- */
+ }
+
+ delete static_cast<RequestDataMap*>(m_pRequestData);
+@@ -743,14 +748,15 @@ void NeonSession::Init()
+ m_nProxyPort );
+ }
+
+- // Note: Uncomment the following if locking support is required
+- /*
+- mNeonLockSession = ne_lock_register( m_pHttpSession );
++ if ( !s_aNeonLockStore )
++ s_aNeonLockStore = ne_lockstore_create();
+
+- if ( mNeonLockSession == NULL )
++ if ( s_aNeonLockStore == NULL )
+ throw DAVException( DAVException::DAV_SESSION_CREATE,
+- theUri::makeConnectionEndPointString() );
+- */
++ NeonUri::makeConnectionEndPointString( m_aHostName, m_nPort ) );
++
++ // Register the lock store
++ ne_lockstore_register( s_aNeonLockStore, m_pHttpSession );
+
+ // Register for redirects.
+ ne_redirect_register( m_pHttpSession );
+@@ -1082,11 +1088,12 @@ void NeonSession::GET( const rtl::OUString & inPath,
+ // -------------------------------------------------------------------
+ // GET
+ // -------------------------------------------------------------------
+-uno::Reference< io::XInputStream >
++uno::Reference< io::XStream >
+ NeonSession::GET( const rtl::OUString & inPath,
+ const std::vector< ::rtl::OUString > & inHeaderNames,
+ DAVResource & ioResource,
+- const DAVRequestEnvironment & rEnv )
++ const DAVRequestEnvironment & rEnv,
++ sal_Bool bAllowEmpty )
+ throw ( DAVException )
+ {
+ osl::Guard< osl::Mutex > theGuard( m_aMutex );
+@@ -1098,16 +1105,23 @@ NeonSession::GET( const rtl::OUString & inPath,
+ ioResource.uri = inPath;
+ ioResource.properties.clear();
+
+- rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream );
+- NeonRequestContext aCtx( xInputStream, inHeaderNames, ioResource );
++ rtl::Reference< NeonInputStream > xStream( new NeonInputStream );
++ NeonRequestContext aCtx( xStream, inHeaderNames, ioResource );
+ int theRetVal = GET( m_pHttpSession,
+ rtl::OUStringToOString(
+ inPath, RTL_TEXTENCODING_UTF8 ),
+ NeonSession_ResponseBlockReader,
+ true,
+ &aCtx );
+- HandleError( theRetVal );
+- return uno::Reference< io::XInputStream >( xInputStream.get() );
++ try {
++ HandleError( theRetVal );
++ }
++ catch ( DAVException const & e )
++ {
++ if ( !bAllowEmpty || ( e.getStatus() != SC_NOT_FOUND ) )
++ throw;
++ }
++ return uno::Reference< io::XStream >( xStream.get() );
+ }
+
+ // -------------------------------------------------------------------
+@@ -1147,22 +1161,38 @@ void NeonSession::PUT( const rtl::OUString & inPath,
+ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException )
+ {
++ // initialization etc. is performed in the other PUT
++
++ uno::Sequence< sal_Int8 > aDataToSend;
++ if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
++ throw DAVException( DAVException::DAV_INVALID_ARG );
++
++ PUT( inPath,
++ reinterpret_cast< const char * >( aDataToSend.getConstArray() ),
++ aDataToSend.getLength(),
++ rEnv );
++}
++
++// -------------------------------------------------------------------
++// PUT
++// -------------------------------------------------------------------
++void NeonSession::PUT( const rtl::OUString &inPath,
++ const char * buffer,
++ size_t size,
++ const DAVRequestEnvironment & rEnv )
++ throw ( DAVException )
++{
+ osl::Guard< osl::Mutex > theGuard( m_aMutex );
+
+ Init();
+
+ m_aEnv = rEnv;
+
+- uno::Sequence< sal_Int8 > aDataToSend;
+- if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) )
+- throw DAVException( DAVException::DAV_INVALID_ARG );
+-
+ int theRetVal = PUT( m_pHttpSession,
+ rtl::OUStringToOString(
+ inPath, RTL_TEXTENCODING_UTF8 ),
+- reinterpret_cast< const char * >(
+- aDataToSend.getConstArray() ),
+- aDataToSend.getLength() );
++ buffer,
++ size );
+
+ HandleError( theRetVal );
+ }
+@@ -1338,9 +1368,7 @@ void NeonSession::DESTROY( const rtl::OUString & inPath,
+ // -------------------------------------------------------------------
+ // LOCK
+ // -------------------------------------------------------------------
+-// Note: Uncomment the following if locking support is required
+-/*
+-void NeonSession::LOCK( const Lock & inLock,
++void NeonSession::LOCK( ucb::Lock & rLock,
+ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException )
+ {
+@@ -1350,16 +1378,13 @@ void NeonSession::LOCK( const Lock & inLock,
+
+ m_aEnv = rEnv;
+
+- Lockit( inLock, true );
++ Lockit( rLock, true );
+ }
+-*/
+
+ // -------------------------------------------------------------------
+ // UNLOCK
+ // -------------------------------------------------------------------
+-// Note: Uncomment the following if locking support is required
+-/*
+-void NeonSession::UNLOCK( const Lock & inLock,
++void NeonSession::UNLOCK( ucb::Lock & rLock,
+ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException )
+ {
+@@ -1369,9 +1394,8 @@ void NeonSession::UNLOCK( const Lock & inLock,
+
+ m_aEnv = rEnv;
+
+- Lockit( inLock, false );
++ Lockit( rLock, false );
+ }
+-*/
+
+ // -------------------------------------------------------------------
+ const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const
+@@ -1410,7 +1434,10 @@ void NeonSession::HandleError( int nError )
+ case NE_ERROR: // Generic error
+ {
+ rtl::OUString aText = rtl::OUString::createFromAscii(
+- ne_get_error( m_pHttpSession ) );
++ ne_get_error( m_pHttpSession ) );
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: got error '%s'\n", rtl::OUStringToOString( aText, RTL_TEXTENCODING_UTF8 ).getStr() );
++#endif
+ throw DAVException( DAVException::DAV_HTTP_ERROR,
+ aText,
+ makeStatusCode( aText ) );
+@@ -1467,77 +1494,151 @@ void NeonSession::HandleError( int nError )
+ }
+ }
+
+-// Note: Uncomment the following if locking support is required
+-/*
+-void NeonSession::Lockit( const Lock & inLock, bool inLockit )
++void NeonSession::Lockit( ucb::Lock & rLock, bool bLockit )
+ throw ( DAVException )
+ {
+ osl::Guard< osl::Mutex > theGuard( m_aMutex );
+
+- // Create the neon lock
+- NeonLock * theLock = new NeonLock;
+- int theRetVal;
++ if ( !s_aNeonLockStore )
++ throw DAVException( DAVException::DAV_INVALID_ARG );
+
+- // Set the lock uri
+- NeonUri theUri( inLock.uri );
+- theLock->uri = const_cast< char * >
+- ( rtl::OUStringToOString(
+- theUri.GetPath(), RTL_TEXTENCODING_UTF8 ).getStr() );
++ ne_uri aUri;
++ ne_uri_parse( rtl::OUStringToOString( m_aEnv.m_aRequestURI, RTL_TEXTENCODING_UTF8 ).getStr(),
++ &aUri );
++
++#if NEON_VERSION < 0x0260
++#define FILLIN( field, val ) aUri.field = aUri.field? aUri.field: strdup( rtl::OUStringToOString( val, RTL_TEXTENCODING_UTF8 ).getStr() )
++ FILLIN( scheme, m_aScheme );
++ FILLIN( host, m_aHostName );
++ aUri.port = aUri.port? aUri.port: m_nPort;
++#undef FILLIN
++#endif
+
+- if ( inLockit )
+- {
+- // Set the lock depth
+- switch( inLock.depth )
+- {
+- case DAVZERO:
+- case DAVINFINITY:
+- theLock->depth = int ( inLock.depth );
+- break;
+- default:
+- throw DAVException( DAVException::DAV_INVALID_ARG );
+- break;
+- }
++ // Create the neon lock
++ NeonLock * theLock = ne_lockstore_findbyuri( s_aNeonLockStore, &aUri );
++ bool bAlreadyExists = false;
++ if ( theLock )
++ bAlreadyExists = true;
++ else
++ {
++ theLock = ne_lock_create();
+
+- // Set the lock scope
+- switch ( inLock.scope )
+- {
+- case EXCLUSIVE:
+- theLock->scope = ne_lockscope_exclusive;
+- break;
+- case SHARED:
+- theLock->scope = ne_lockscope_shared;
+- break;
+- default:
+- throw DAVException( DAVException::DAV_INVALID_ARG );
+- break;
+- }
++ // Set the lock uri
++ theLock->uri = aUri;
+
+- // Set the lock owner
+- const char * theOwner = rtl::OUStringToOString( inLock.owner,
+- RTL_TEXTENCODING_UTF8 );
+- theLock->owner = const_cast< char * > ( theOwner );
++ // Set the lock depth
++ switch( rLock.Depth )
++ {
++ case ucb::LockDepth_ZERO: theLock->depth = NE_DEPTH_ZERO; break;
++ case ucb::LockDepth_ONE: theLock->depth = NE_DEPTH_ONE; break;
++ case ucb::LockDepth_INFINITY: theLock->depth = NE_DEPTH_INFINITE; break;
++ default:
++ throw DAVException( DAVException::DAV_INVALID_ARG );
++ }
+
+- // Set the lock timeout
+- // Note: Neon ignores the timeout
+- //theLock->timeout = inLock.timeout;
++ // Set the lock scope
++ switch ( rLock.Scope )
++ {
++ case ucb::LockScope_EXCLUSIVE: theLock->scope = ne_lockscope_exclusive; break;
++ case ucb::LockScope_SHARED: theLock->scope = ne_lockscope_shared; break;
++ default:
++ throw DAVException( DAVException::DAV_INVALID_ARG );
++ break;
++ }
+
+- theRetVal = ne_lock( m_pHttpSession, theLock );
+- }
+- else
+- {
++ // Set the lock owner
++ rtl::OUString aValue;
++ rLock.Owner >>= aValue;
+
+- // Set the lock token
+- rtl::OUString theToken = inLock.locktoken.getConstArray()[ 0 ];
+- theLock->token = const_cast< char * >
+- ( rtl::OUStringToOString(
+- theToken, RTL_TEXTENCODING_UTF8 ).getStr() );
++ theLock->owner = strdup( rtl::OUStringToOString( aValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+- theRetVal = ne_unlock( m_pHttpSession, theLock );
+- }
++ // Set the lock timeout
++ // We re-new the lock while the stream is open
++ theLock->timeout = rLock.Timeout;
++ }
+
+- HandleError( theRetVal );
++ if ( bLockit )
++ {
++ int nRet;
++ if ( !bAlreadyExists )
++ {
++ nRet = ne_lock( m_pHttpSession, theLock );
++
++ if ( nRet == NE_OK )
++ {
++ ne_lockstore_add( s_aNeonLockStore, theLock );
++
++ uno::Sequence< rtl::OUString > aTokens( 1 );
++ aTokens[0] = rtl::OUString::createFromAscii( theLock->token );
++ rLock.LockTokens = aTokens;
++
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: locked the URL, the token is: %s\n", theLock->token );
++#endif
++ }
++ }
++ else
++ {
++#if NEON_VERSION >= 0x0260
++ nRet = ne_lock_refresh( m_pHttpSession, theLock );
++#else
++ // workaround for a bug in neon 0.24
++ // we have to call with a bigger structure that is used internally
++ // and initialize parts of it
++
++ struct lock_ctx
++ {
++ struct ne_lock active; /* activelock */
++ char *token; /* the token we're after. */
++ int found;
++ ne_buffer *cdata;
++ };
++
++ struct lock_ctx ctx;
++
++ memset( &ctx, 0, sizeof ctx );
++ ctx.cdata = ne_buffer_create();
++
++ memcpy( &ctx, theLock, sizeof( *theLock ) );
++ nRet = ne_lock_refresh( m_pHttpSession, reinterpret_cast<NeonLock*>( &ctx ) );
++
++ ne_buffer_destroy( ctx.cdata );
++#endif
++ }
++
++ if ( ( nRet == NE_ERROR ) && ( getStatusCode( m_pHttpSession ) == SC_LOCKED ) )
++ {
++ ucbhelper::cancelCommandExecution( ucb::IOErrorCode_LOCKING_VIOLATION,
++ uno::Sequence< uno::Any >( 0 ), // FIXME more info about the file?
++ m_aEnv.m_xEnv,
++ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "a locking error occured" ) ),
++ uno::Reference< ucb::XCommandProcessor >() );
++ }
++#if OSL_DEBUG_LEVEL > 0
++ else if ( nRet == NE_OK )
++ fprintf( stderr, "WebDAV: locked/refreshed lock OK\n" );
++ else
++ fprintf( stderr, "WebDAV: failed to lock the file, status code is: %d\n", getStatusCode( m_pHttpSession ) );
++#endif
++ }
++ else
++ {
++ // Set the lock token
++ if ( rLock.LockTokens.getLength() > 0 )
++ {
++ rtl::OUString theToken = rLock.LockTokens.getConstArray()[ 0 ];
++ theLock->token = strdup( rtl::OUStringToOString( theToken, RTL_TEXTENCODING_UTF8 ).getStr() );
++
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: going to unlock the URL, the token is: %s\n", theLock->token );
++#endif
++
++ ne_unlock( m_pHttpSession, theLock );
++ ne_lockstore_remove( s_aNeonLockStore, theLock );
++ // FIXME even ne_lock_destroy( theLock )?
++ }
++ }
+ }
+-*/
+
+ // -------------------------------------------------------------------
+ namespace {
+diff --git ucb/source/ucp/webdav/NeonSession.hxx ucb/source/ucp/webdav/NeonSession.hxx
+index 2dbb7af..343cb2c 100644
+--- ucb/source/ucp/webdav/NeonSession.hxx
++++ ucb/source/ucp/webdav/NeonSession.hxx
+@@ -57,6 +57,7 @@ class NeonSession : public DAVSession
+ rtl::OUString m_aScheme;
+ rtl::OUString m_aHostName;
+ rtl::OUString m_aProxyName;
++ rtl::OUString m_aUserInfo;
+ sal_Int32 m_nPort;
+ sal_Int32 m_nProxyPort;
+ HttpSession * m_pHttpSession;
+@@ -70,8 +71,7 @@ class NeonSession : public DAVSession
+ // moment.
+ DAVRequestEnvironment m_aEnv;
+
+- // Note: Uncomment the following if locking support is required
+- // NeonLockSession * mNeonLockSession;
++ static NeonLockStore *s_aNeonLockStore;
+
+ static bool m_bGlobalsInited;
+
+@@ -92,6 +92,8 @@ class NeonSession : public DAVSession
+ const DAVRequestEnvironment & getRequestEnvironment() const
+ { return m_aEnv; }
+
++ const rtl::OUString & getUserInfo() const { return m_aUserInfo; }
++
+ virtual void
+ OPTIONS( const ::rtl::OUString & inPath,
+ DAVCapabilities & outCapabilities,
+@@ -142,11 +144,12 @@ class NeonSession : public DAVSession
+ throw ( DAVException );
+
+ virtual com::sun::star::uno::Reference<
+- com::sun::star::io::XInputStream >
++ com::sun::star::io::XStream >
+ GET( const ::rtl::OUString & inPath,
+ const std::vector< ::rtl::OUString > & inHeaderNames,
+ DAVResource & ioResource,
+- const DAVRequestEnvironment & rEnv )
++ const DAVRequestEnvironment & rEnv,
++ sal_Bool bAllowEmpty = sal_False )
+ throw ( DAVException );
+
+ virtual void
+@@ -165,6 +168,13 @@ class NeonSession : public DAVSession
+ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException );
+
++ virtual void
++ PUT( const ::rtl::OUString & inPath,
++ const char * buffer,
++ size_t size,
++ const DAVRequestEnvironment & rEnv )
++ throw ( DAVException );
++
+ virtual com::sun::star::uno::Reference<
+ com::sun::star::io::XInputStream >
+ POST( const rtl::OUString & inPath,
+@@ -209,16 +219,13 @@ class NeonSession : public DAVSession
+ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException );
+
+- // Note: Uncomment the following if locking support is required
+- /*
+- virtual void LOCK (const Lock & inLock,
+- const DAVRequestEnvironment & rEnv )
++ virtual void LOCK ( com::sun::star::ucb::Lock & rLock,
++ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException );
+
+- virtual void UNLOCK (const Lock & inLock,
+- const DAVRequestEnvironment & rEnv )
++ virtual void UNLOCK ( com::sun::star::ucb::Lock & rLock,
++ const DAVRequestEnvironment & rEnv )
+ throw ( DAVException );
+- */
+
+ // helpers
+ const rtl::OUString & getHostName() const { return m_aHostName; }
+@@ -243,9 +250,8 @@ class NeonSession : public DAVSession
+
+ const ucbhelper::InternetProxyServer & getProxySettings() const;
+
+- // Note: Uncomment the following if locking support is required
+- // void Lockit( const Lock & inLock, bool inLockit )
+- // throw ( DAVException );
++ void Lockit( com::sun::star::ucb::Lock & rLock, bool bLockit )
++ throw ( DAVException );
+
+ // low level GET implementation, used by public GET implementations
+ static int GET( ne_session * sess,
+diff --git ucb/source/ucp/webdav/NeonTypes.hxx ucb/source/ucp/webdav/NeonTypes.hxx
+index 08c7d07..6e80fee 100644
+--- ucb/source/ucp/webdav/NeonTypes.hxx
++++ ucb/source/ucp/webdav/NeonTypes.hxx
+@@ -35,6 +35,7 @@
+ #include <ne_utils.h>
+ #include <ne_basic.h>
+ #include <ne_props.h>
++#include <ne_locks.h>
+
+ typedef ne_session HttpSession;
+ typedef ne_status HttpStatus;
+@@ -43,4 +44,7 @@ typedef ne_server_capabilities HttpServerCapabilities;
+ typedef ne_propname NeonPropName;
+ typedef ne_prop_result_set NeonPropFindResultSet;
+
++typedef ne_lock_store NeonLockStore;
++typedef struct ne_lock NeonLock;
++
+ #endif // _NEONTYPES_HXX_
+diff --git ucb/source/ucp/webdav/webdavcontent.cxx ucb/source/ucp/webdav/webdavcontent.cxx
+index 38f590e..84cc057 100644
+--- ucb/source/ucp/webdav/webdavcontent.cxx
++++ ucb/source/ucp/webdav/webdavcontent.cxx
+@@ -48,20 +48,17 @@
+ #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
+ #include <com/sun/star/beans/PropertyValue.hpp>
+ #include <com/sun/star/io/XActiveDataSink.hpp>
++#include <com/sun/star/io/XActiveDataStreamer.hpp>
+ #include <com/sun/star/io/XOutputStream.hpp>
+ #include <com/sun/star/lang/IllegalAccessException.hpp>
+ #include "com/sun/star/ucb/AuthenticationRequest.hpp"
+ #include <com/sun/star/ucb/CommandFailedException.hpp>
+ #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
+ #include <com/sun/star/ucb/InsertCommandArgument.hpp>
+-#ifndef _COM_SUN_STAR_UCB_INTERACTIVEBADTRANSFRERURLEXCEPTION_HPP_
+ #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
+-#endif
+ #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+ #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
+-#ifndef _COM_SUN_STAR_UCB_INTERACTIVENETWORKGENBERALEXCEPTION_HPP_
+ #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
+-#endif
+ #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
+ #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
+ #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
+@@ -90,6 +87,8 @@
+ #include "NeonUri.hxx"
+ #include "UCBDeadPropertyValue.hxx"
+
++#include "NeonInputStream.hxx"
++
+ using namespace com::sun::star;
+ using namespace webdav_ucp;
+
+@@ -353,7 +352,8 @@ Content::Content(
+ m_eResourceType( UNKNOWN ),
+ m_pProvider( pProvider ),
+ m_bTransient( sal_False ),
+- m_bCollection( sal_False )
++ m_bCollection( sal_False ),
++ m_bForceReadOnly( sal_False )
+ {
+ try
+ {
+@@ -624,6 +624,11 @@ uno::Any SAL_CALL Content::execute(
+ ucb::CommandAbortedException,
+ uno::RuntimeException )
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: Execute command '%s'\n",
++ rtl::OUStringToOString( aCommand.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
++#endif
++
+ uno::Any aRet;
+
+ if ( aCommand.Name.equalsAsciiL(
+@@ -1343,6 +1348,31 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues(
+ uno::Reference< ucb::XContentIdentifier > xIdentifier;
+ rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider;
+
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: getPropertyValues: answering the following properties: " );
++ for ( int i = 0; i < rProperties.getLength(); ++i )
++ fprintf( stderr, " %s,",
++ rtl::OUStringToOString( rProperties[i].Name, RTL_TEXTENCODING_UTF8 ).getStr() );
++ fprintf( stderr, "\n" );
++#endif
++
++ // WebDAV supports XActiveDataStreamer
++ // We have to return TRUE on
++ // - SupportsActiveStreaming - always
++ // - IsReadOnly - if we forced read only due to failed locking
++ if ( rProperties.getLength() == 1 )
++ {
++ if ( rProperties[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "SupportsActiveStreaming" ) ) ||
++ ( rProperties[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) && m_bForceReadOnly ) )
++ {
++ rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
++ = new ::ucbhelper::PropertyValueSet( m_xSMgr );
++ xRow->appendBoolean( rProperties[0], sal_True );
++
++ return uno::Reference< sdbc::XRow >( xRow.get() );
++ }
++ }
++
+ const ResourceType & rType = getResourceType( xEnv );
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+@@ -1463,8 +1493,13 @@ uno::Reference< sdbc::XRow > Content::getPropertyValues(
+
+ if ( !bNetworkAccessAllowed )
+ {
+- cancelCommandExecution( e, xEnv );
+- // unreachable
++ if ( e.getStatus() == SC_NOT_FOUND )
++ xProps.reset();
++ else
++ {
++ cancelCommandExecution( e, xEnv );
++ // unreachable
++ }
+ }
+ }
+ }
+@@ -2023,30 +2058,90 @@ uno::Any Content::open(
+ }
+ }
+
+- if ( rArg.Sink.is() )
+- {
+- // Open document.
++ if ( !rArg.Sink.is() )
++ return aRet;
+
+- if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
+- ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
+- {
+- // Currently(?) unsupported.
+- ucbhelper::cancelCommandExecution(
++ // Open document.
++
++ if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
++ ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
++ {
++ // Currently(?) unsupported.
++ ucbhelper::cancelCommandExecution(
+ uno::makeAny(
+ ucb::UnsupportedOpenModeException(
+- rtl::OUString(),
+- static_cast< cppu::OWeakObject * >( this ),
+- sal_Int16( rArg.Mode ) ) ),
++ rtl::OUString(),
++ static_cast< cppu::OWeakObject * >( this ),
++ sal_Int16( rArg.Mode ) ) ),
+ xEnv );
++ // Unreachable
++ }
++
++ rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
++ uno::Reference< io::XOutputStream > xOut
++ = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
++ if ( xOut.is() )
++ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XOutputStream\n" );
++#endif
++ // PUSH: write data
++ try
++ {
++ std::auto_ptr< DAVResourceAccess > xResAccess;
++
++ {
++ osl::MutexGuard aGuard( m_aMutex );
++
++ // throw away previously cached headers.
++// m_xCachedProps.reset();
++
++ xResAccess.reset(
++ new DAVResourceAccess( *m_xResAccess.get() ) );
++ }
++
++ DAVResource aResource;
++ std::vector< rtl::OUString > aHeaders;
++ // // Obtain list containing all HTTP headers that can
++ // // be mapped to UCB properties.
++ // ContentProperties::getMappableHTTPHeaders( aHeaders );
++
++ xResAccess->GET( xOut, aHeaders, aResource, xEnv );
++
++ {
++ osl::MutexGuard aGuard( m_aMutex );
++
++ // cache headers.
++// m_xCachedProps.reset( new ContentProperties( aResource ) );
++ std::vector< DAVPropertyValue >::const_iterator it = aResource.properties.begin();
++ std::vector< DAVPropertyValue >::const_iterator end = aResource.properties.end();
++ while ( it != end )
++ {
++ DAVPropertyValue aProp = (*it++);
++ m_xCachedProps->addProperty( aProp.Name, aProp.Value, true);
++ }
++
++ m_xResAccess.reset(
++ new DAVResourceAccess( *xResAccess.get() ) );
++ }
++ }
++ catch ( DAVException const & e )
++ {
++ cancelCommandExecution( e, xEnv );
+ // Unreachable
+ }
+-
+- rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
+- uno::Reference< io::XOutputStream > xOut
+- = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
+- if ( xOut.is() )
++ }
++ else
++ {
++ uno::Reference< io::XActiveDataSink > xDataSink
++ = uno::Reference< io::XActiveDataSink >( rArg.Sink,
++ uno::UNO_QUERY );
++ if ( xDataSink.is() )
+ {
+- // PUSH: write data
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataSink\n" );
++#endif
++ // PULL: wait for client read
+ try
+ {
+ std::auto_ptr< DAVResourceAccess > xResAccess;
+@@ -2060,33 +2155,27 @@ uno::Any Content::open(
+ xResAccess.reset(
+ new DAVResourceAccess( *m_xResAccess.get() ) );
+ }
+-
++ // fill inputsream sync; return if all data present
+ DAVResource aResource;
+ std::vector< rtl::OUString > aHeaders;
+-// // Obtain list containing all HTTP headers that can
+-// // be mapped to UCB properties.
+-// ContentProperties::getMappableHTTPHeaders( aHeaders );
+-
+- xResAccess->GET( xOut, aHeaders, aResource, xEnv );
++ // // Obtain list containing all HTTP headers that can
++ // // be mapped to UCB properties.
++ // ContentProperties::getMappableHTTPHeaders( aHeaders );
++ uno::Reference< io::XInputStream > xIn
++ = xResAccess->GET( aHeaders, aResource, xEnv )->getInputStream();
+
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // cache headers.
+ // m_xCachedProps.reset( new ContentProperties( aResource ) );
+- std::vector< DAVPropertyValue >::const_iterator it = aResource.properties.begin();
+- std::vector< DAVPropertyValue >::const_iterator end = aResource.properties.end();
+- while ( it != end )
+- {
+- DAVPropertyValue aProp = (*it++);
+- m_xCachedProps->addProperty( aProp.Name, aProp.Value, true);
+- }
+-
+-
+
+ m_xResAccess.reset(
+ new DAVResourceAccess( *xResAccess.get() ) );
++
+ }
++
++ xDataSink->setInputStream( xIn );
+ }
+ catch ( DAVException const & e )
+ {
+@@ -2096,15 +2185,24 @@ uno::Any Content::open(
+ }
+ else
+ {
+- uno::Reference< io::XActiveDataSink > xDataSink
+- = uno::Reference< io::XActiveDataSink >( rArg.Sink,
+- uno::UNO_QUERY );
+- if ( xDataSink.is() )
++ uno::Reference< io::XActiveDataStreamer > xDataStreamer
++ = uno::Reference< io::XActiveDataStreamer >( rArg.Sink,
++ uno::UNO_QUERY );
++ if ( xDataStreamer.is() && !m_bForceReadOnly )
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataStreamer\n" );
++#endif
++ // prepare the lock
++ ucb::Lock aLock;
++ aLock.Depth = ucb::LockDepth_ZERO;
++ aLock.Scope = ucb::LockScope_EXCLUSIVE;
++ aLock.Timeout = 3*60; // 3 minutes
++
+ // PULL: wait for client read
++ std::auto_ptr< DAVResourceAccess > xResAccess;
+ try
+ {
+- std::auto_ptr< DAVResourceAccess > xResAccess;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+@@ -2118,43 +2216,69 @@ uno::Any Content::open(
+ // fill inputsream sync; return if all data present
+ DAVResource aResource;
+ std::vector< rtl::OUString > aHeaders;
+-// // Obtain list containing all HTTP headers that can
+-// // be mapped to UCB properties.
+-// ContentProperties::getMappableHTTPHeaders( aHeaders );
++ // // Obtain list containing all HTTP headers that can
++ // // be mapped to UCB properties.
++ // ContentProperties::getMappableHTTPHeaders( aHeaders );
+
+- uno::Reference< io::XInputStream > xIn
+- = xResAccess->GET( aHeaders, aResource, xEnv );
++ try {
++ xResAccess->LOCK( aLock, xEnv );
++ }
++ catch ( ucb::CommandFailedException const &e )
++ {
++ // stream locked?
++ ucb::InteractiveIOException aIoException;
++ if ( ( e.Reason >>= aIoException ) && ( aIoException.Code == ucb::IOErrorCode_LOCKING_VIOLATION ) )
++ {
++ // yes => we must be read only at the next try
++ m_bForceReadOnly = sal_True;
++ }
++
++ throw;
++ }
++
++ uno::Reference< io::XStream > xStream
++ = xResAccess->GET( aHeaders, aResource, xEnv, sal_True );
++
++ // pass the lock to the stream
++ static_cast< NeonInputStream* >( xStream.get() )->SetLock( aLock, m_xResAccess->getURL() );
+
+ {
++
+ osl::MutexGuard aGuard( m_aMutex );
+- // m_xCachedProps.reset(
+- // new ContentProperties( aResource ) );
++// m_xCachedProps.reset(
++// new ContentProperties( aResource ) );
+
+ m_xResAccess.reset(
+ new DAVResourceAccess( *xResAccess.get() ) );
+
+ }
+
+- xDataSink->setInputStream( xIn );
++ xDataStreamer->setStream( xStream );
+ }
+ catch ( DAVException const & e )
+ {
++ xResAccess->UNLOCK( aLock, xEnv );
++ m_bForceReadOnly = sal_False;
++
+ cancelCommandExecution( e, xEnv );
+ // Unreachable
+ }
+ }
+ else
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: unsupported rArg.Sink\n" );
++#endif
+ // Note: aOpenCommand.Sink may contain an XStream
+ // implementation. Support for this type of
+ // sink is optional...
+ ucbhelper::cancelCommandExecution(
+- uno::makeAny(
+- ucb::UnsupportedDataSinkException(
+- rtl::OUString(),
+- static_cast< cppu::OWeakObject * >( this ),
+- rArg.Sink ) ),
+- xEnv );
++ uno::makeAny(
++ ucb::UnsupportedDataSinkException(
++ rtl::OUString(),
++ static_cast< cppu::OWeakObject * >( this ),
++ rArg.Sink ) ),
++ xEnv );
+ // Unreachable
+ }
+ }
+@@ -2172,6 +2296,9 @@ void Content::post(
+ uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
+ if ( xSink.is() )
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataSink\n" );
++#endif
+ try
+ {
+ std::auto_ptr< DAVResourceAccess > xResAccess;
+@@ -2206,6 +2333,9 @@ void Content::post(
+ uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
+ if ( xResult.is() )
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XOutputStream\n" );
++#endif
+ try
+ {
+ std::auto_ptr< DAVResourceAccess > xResAccess;
+@@ -2235,6 +2365,9 @@ void Content::post(
+ }
+ else
+ {
++#if OSL_DEBUG_LEVEL > 0
++ fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataStreamer (or something)\n" );
++#endif
+ ucbhelper::cancelCommandExecution(
+ uno::makeAny(
+ ucb::UnsupportedDataSinkException(
+@@ -2575,19 +2708,19 @@ void Content::transfer(
+ //
+ const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
+ if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
+- {
+- sourceURI.SetScheme(
+- rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
+- }
+- else if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
++ RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ||
++ aScheme.equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ||
++ aScheme.equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAV_URL_SCHEME ) ) )
+ {
+ sourceURI.SetScheme(
+ rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
+ }
+ else if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
++ RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ||
++ aScheme.equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAVS_URL_SCHEME ) ) )
+ {
+ sourceURI.SetScheme(
+ rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
+@@ -2611,13 +2744,23 @@ void Content::transfer(
+ }
+
+ if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
++ RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ||
++ targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ||
++ targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAV_URL_SCHEME ) ) )
++ {
+ targetURI.SetScheme(
+ rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
++ }
+ else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
++ RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ||
++ targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAVS_URL_SCHEME ) ) )
++ {
+ targetURI.SetScheme(
+- rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
++ rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
++ }
+
+ // @@@ This implementation of 'transfer' only works
+ // if the source and target are located at same host.
+diff --git ucb/source/ucp/webdav/webdavcontent.hxx ucb/source/ucp/webdav/webdavcontent.hxx
+index e945f78..cf91688 100644
+--- ucb/source/ucp/webdav/webdavcontent.hxx
++++ ucb/source/ucp/webdav/webdavcontent.hxx
+@@ -90,6 +90,7 @@ class Content : public ::ucbhelper::ContentImplHelper,
+ ContentProvider* m_pProvider; // No need for a ref, base class holds object
+ sal_Bool m_bTransient;
+ sal_Bool m_bCollection;
++ sal_Bool m_bForceReadOnly;
+
+ private:
+ virtual com::sun::star::uno::Sequence< com::sun::star::beans::Property >
+diff --git ucb/source/ucp/webdav/webdavcontentcaps.cxx ucb/source/ucp/webdav/webdavcontentcaps.cxx
+index ba3d4bc..f5c5652 100644
+--- ucb/source/ucp/webdav/webdavcontentcaps.cxx
++++ ucb/source/ucp/webdav/webdavcontentcaps.cxx
+@@ -263,6 +263,24 @@ bool ContentProvider::getProperty(
+ -1,
+ getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
+ beans::PropertyAttribute::BOUND ) );
++
++ m_pProps->insert(
++ beans::Property(
++ rtl::OUString(
++ RTL_CONSTASCII_USTRINGPARAM( "SupportsActiveStreaming" ) ),
++ -1,
++ getCppuBooleanType(),
++ beans::PropertyAttribute::BOUND
++ | beans::PropertyAttribute::READONLY ) );
++
++ m_pProps->insert(
++ beans::Property(
++ rtl::OUString(
++ RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ),
++ -1,
++ getCppuBooleanType(),
++ beans::PropertyAttribute::BOUND
++ | beans::PropertyAttribute::READONLY ) );
+ }
+ }
+
+diff --git ucb/source/ucp/webdav/webdavprovider.cxx ucb/source/ucp/webdav/webdavprovider.cxx
+index 67f670f..5675c2d 100644
+--- ucb/source/ucp/webdav/webdavprovider.cxx
++++ ucb/source/ucp/webdav/webdavprovider.cxx
+@@ -36,6 +36,9 @@
+ **************************************************************************
+
+ *************************************************************************/
++
++#include <string.h>
++
+ #include <ucbhelper/contentidentifier.hxx>
+ #include "webdavprovider.hxx"
+ #include "webdavcontent.hxx"
+@@ -138,7 +141,11 @@ ContentProvider::queryContent(
+ RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) &&
+ !aScheme.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) &&
+- !aScheme.equalsAsciiL(
++ !aScheme.equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAV_URL_SCHEME ) ) &&
++ !aScheme.equalsAsciiL(
++ RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAVS_URL_SCHEME ) ) &&
++ !aScheme.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM( FTP_URL_SCHEME ) ) )
+ throw ucb::IllegalIdentifierException();
+
+@@ -157,32 +164,27 @@ ContentProvider::queryContent(
+ uno::Reference< ucb::XContentIdentifier > xCanonicId;
+
+ bool bNewId = false;
+- if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
++ struct {
++ const char *from;
++ const char *to;
++ } const *pScheme, pReplace[] = {
++ { WEBDAV_URL_SCHEME, HTTP_URL_SCHEME },
++ { DAV_URL_SCHEME, HTTP_URL_SCHEME },
++ { DAVS_URL_SCHEME, HTTPS_URL_SCHEME },
++ { PLAIN_WEBDAV_URL_SCHEME, HTTP_URL_SCHEME },
++ { PLAIN_WEBDAVS_URL_SCHEME, HTTPS_URL_SCHEME },
++ { NULL, NULL }
++ };
++ for ( pScheme = pReplace; pScheme->from ; ++pScheme )
+ {
+- aURL = aURL.replaceAt( 0,
+- WEBDAV_URL_SCHEME_LENGTH,
+- rtl::OUString::createFromAscii(
+- HTTP_URL_SCHEME ) );
+- bNewId = true;
+- }
+- else if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
+- {
+- aURL = aURL.replaceAt( 0,
+- DAV_URL_SCHEME_LENGTH,
+- rtl::OUString::createFromAscii(
+- HTTP_URL_SCHEME ) );
+- bNewId = true;
+- }
+- else if ( aScheme.equalsAsciiL(
+- RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
+- {
+- aURL = aURL.replaceAt( 0,
+- DAVS_URL_SCHEME_LENGTH,
+- rtl::OUString::createFromAscii(
+- HTTPS_URL_SCHEME ) );
+- bNewId = true;
++ if ( aScheme.equalsAscii( pScheme->from ) )
++ {
++ aURL = aURL.replaceAt( 0,
++ strlen( pScheme->from ),
++ rtl::OUString::createFromAscii( pScheme->to ) );
++ bNewId = true;
++ break;
++ }
+ }
+
+ sal_Int32 nPos = aURL.lastIndexOf( '/' );
+@@ -232,4 +234,3 @@ ContentProvider::queryContent(
+
+ return xContent;
+ }
+-
+diff --git ucb/source/ucp/webdav/webdavprovider.hxx ucb/source/ucp/webdav/webdavprovider.hxx
+index 4ca8395..d9fc947 100644
+--- ucb/source/ucp/webdav/webdavprovider.hxx
++++ ucb/source/ucp/webdav/webdavprovider.hxx
+@@ -52,13 +52,10 @@ namespace webdav_ucp {
+ // contents ) according to this scheme.
+ #define WEBDAV_URL_SCHEME \
+ "vnd.sun.star.webdav"
+-#define WEBDAV_URL_SCHEME_LENGTH 19
+
+ #define HTTP_URL_SCHEME "http"
+-#define HTTP_URL_SCHEME_LENGTH 4
+
+ #define HTTPS_URL_SCHEME "https"
+-#define HTTPS_URL_SCHEME_LENGTH 5
+
+ #define DAV_URL_SCHEME "dav"
+ #define DAV_URL_SCHEME_LENGTH 3
+@@ -70,6 +67,12 @@ namespace webdav_ucp {
+
+ #define FTP_URL_SCHEME "ftp"
+
++#define DAV_URL_SCHEME "dav"
++#define DAVS_URL_SCHEME "davs"
++
++#define PLAIN_WEBDAV_URL_SCHEME "webdav"
++#define PLAIN_WEBDAVS_URL_SCHEME "webdavs"
++
+ #define HTTP_CONTENT_TYPE \
+ "application/" HTTP_URL_SCHEME "-content"
+
+diff --git unotools/source/ucbhelper/ucblockbytes.cxx unotools/source/ucbhelper/ucblockbytes.cxx
+index be78f73..6a7860c 100644
+--- unotools/source/ucbhelper/ucblockbytes.cxx
++++ unotools/source/ucbhelper/ucblockbytes.cxx
+@@ -964,6 +964,10 @@ static sal_Bool UCBOpenContentSync(
+ if( ! aScheme.equalsIgnoreAsciiCaseAscii("http") &&
+ ! aScheme.equalsIgnoreAsciiCaseAscii("https") &&
+ ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") &&
++ ! aScheme.equalsIgnoreAsciiCaseAscii("dav") &&
++ ! aScheme.equalsIgnoreAsciiCaseAscii("davs") &&
++ ! aScheme.equalsIgnoreAsciiCaseAscii("webdav") &&
++ ! aScheme.equalsIgnoreAsciiCaseAscii("webdavs") &&
+ ! aScheme.equalsIgnoreAsciiCaseAscii("ftp"))
+ return _UCBOpenContentSync(
+ xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler);
+@@ -1541,7 +1545,13 @@ ErrCode UcbLockBytes::Flush() const
+ Reference <XOutputStream > xOutputStream = getOutputStream_Impl();
+ if ( !xOutputStream.is() )
+ return ERRCODE_IO_CANTWRITE;
+- xOutputStream->flush();
++ try {
++ xOutputStream->flush();
++ }
++ catch (...)
++ {
++ return ERRCODE_IO_CANTWRITE;
++ }
+ return ERRCODE_NONE;
+ }
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]