1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sharecontrolfile.cxx,v $
10 * $Revision: 1.6.82.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
36 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
37 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
38 #include <com/sun/star/ucb/XContent.hpp>
39 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
40 #include <com/sun/star/ucb/InteractiveIOException.hpp>
41 #include <com/sun/star/io/WrongFormatException.hpp>
44 #include <osl/security.hxx>
45 #include <osl/socket.hxx>
47 #include <rtl/string.hxx>
48 #include <rtl/ustring.hxx>
49 #include <rtl/strbuf.hxx>
50 #include <rtl/ustrbuf.hxx>
52 #include <comphelper/processfactory.hxx>
53 #include <ucbhelper/content.hxx>
55 #include <tools/urlobj.hxx>
56 #include <tools/stream.hxx>
57 #include <unotools/bootstrap.hxx>
58 #include <unotools/streamwrap.hxx>
60 #include <svtools/useroptions.hxx>
62 #include <svtools/sharecontrolfile.hxx>
64 using namespace ::com::sun::star
;
68 // ----------------------------------------------------------------------
69 ShareControlFile::ShareControlFile( const ::rtl::OUString
& aOrigURL
, const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
)
70 : LockFileCommon( aOrigURL
, xFactory
, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".~sharing." ) ) )
75 throw io::NotConnectedException();
78 // ----------------------------------------------------------------------
79 ShareControlFile::~ShareControlFile()
85 catch( uno::Exception
& )
89 // ----------------------------------------------------------------------
90 void ShareControlFile::OpenStream()
92 // if it is called outside of constructor the mutex must be locked already
94 if ( !m_xStream
.is() && m_aURL
.getLength() )
96 uno::Reference
< ucb::XCommandEnvironment
> xDummyEnv
;
97 ::ucbhelper::Content aContent
= ::ucbhelper::Content( m_aURL
, xDummyEnv
);
99 uno::Reference
< ucb::XContentIdentifier
> xContId( aContent
.get().is() ? aContent
.get()->getIdentifier() : 0 );
100 if ( !xContId
.is() || !xContId
->getContentProviderScheme().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "file" ) ) ) )
101 throw io::IOException(); // the implementation supports only local files for now
103 uno::Reference
< io::XStream
> xStream
;
105 // Currently the locking of the original document is intended to be used.
106 // That means that the shared file should be accessed only when the original document is locked and only by user who has locked the document.
107 // TODO/LATER: should the own file locking be used?
111 xStream
= aContent
.openWriteableStreamNoLock();
113 catch ( ucb::InteractiveIOException
const & e
)
115 if ( e
.Code
== ucb::IOErrorCode_NOT_EXISTING
)
118 SvMemoryStream
aStream(0,0);
119 uno::Reference
< io::XInputStream
> xInput( new ::utl::OInputStreamWrapper( aStream
) );
120 ucb::InsertCommandArgument aInsertArg
;
121 aInsertArg
.Data
= xInput
;
122 aInsertArg
.ReplaceExisting
= sal_False
;
123 aContent
.executeCommand( rtl::OUString::createFromAscii( "insert" ), uno::makeAny( aInsertArg
) );
125 // try to let the file be hidden if possible
127 aContent
.setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ), uno::makeAny( sal_True
) );
128 } catch( uno::Exception
& ) {}
130 // Try to open one more time
131 xStream
= aContent
.openWriteableStreamNoLock();
137 m_xSeekable
.set( xStream
, uno::UNO_QUERY_THROW
);
138 m_xInputStream
.set( xStream
->getInputStream(), uno::UNO_QUERY_THROW
);
139 m_xOutputStream
.set( xStream
->getOutputStream(), uno::UNO_QUERY_THROW
);
140 m_xTruncate
.set( m_xOutputStream
, uno::UNO_QUERY_THROW
);
145 // ----------------------------------------------------------------------
146 void ShareControlFile::Close()
148 // if it is called outside of destructor the mutex must be locked
150 if ( m_xStream
.is() )
154 if ( m_xInputStream
.is() )
155 m_xInputStream
->closeInput();
156 if ( m_xOutputStream
.is() )
157 m_xOutputStream
->closeOutput();
159 catch( uno::Exception
& )
162 m_xStream
= uno::Reference
< io::XStream
>();
163 m_xInputStream
= uno::Reference
< io::XInputStream
>();
164 m_xOutputStream
= uno::Reference
< io::XOutputStream
>();
165 m_xSeekable
= uno::Reference
< io::XSeekable
>();
166 m_xTruncate
= uno::Reference
< io::XTruncate
>();
167 m_aUsersData
.realloc( 0 );
171 // ----------------------------------------------------------------------
172 uno::Sequence
< uno::Sequence
< ::rtl::OUString
> > ShareControlFile::GetUsersData()
174 ::osl::MutexGuard
aGuard( m_aMutex
);
177 throw io::NotConnectedException();
179 if ( !m_aUsersData
.getLength() )
181 sal_Int64 nLength
= m_xSeekable
->getLength();
182 if ( nLength
> SAL_MAX_INT32
)
183 throw uno::RuntimeException();
185 uno::Sequence
< sal_Int8
> aBuffer( (sal_Int32
)nLength
);
186 m_xSeekable
->seek( 0 );
188 sal_Int32 nRead
= m_xInputStream
->readBytes( aBuffer
, (sal_Int32
)nLength
);
190 while ( nLength
> 0 )
192 uno::Sequence
< sal_Int8
> aTmpBuf( (sal_Int32
)nLength
);
193 nRead
= m_xInputStream
->readBytes( aTmpBuf
, (sal_Int32
)nLength
);
194 if ( nRead
> nLength
)
195 throw uno::RuntimeException();
197 for ( sal_Int32 nInd
= 0; nInd
< nRead
; nInd
++ )
198 aBuffer
[aBuffer
.getLength() - (sal_Int32
)nLength
+ nInd
] = aTmpBuf
[nInd
];
202 m_aUsersData
= ParseList( aBuffer
);
208 // ----------------------------------------------------------------------
209 void ShareControlFile::SetUsersDataAndStore( const uno::Sequence
< uno::Sequence
< ::rtl::OUString
> >& aUsersData
)
211 ::osl::MutexGuard
aGuard( m_aMutex
);
214 throw io::NotConnectedException();
216 if ( !m_xTruncate
.is() || !m_xOutputStream
.is() || !m_xSeekable
.is() )
217 throw uno::RuntimeException();
219 m_xTruncate
->truncate();
220 m_xSeekable
->seek( 0 );
222 ::rtl::OUStringBuffer aBuffer
;
223 for ( sal_Int32 nInd
= 0; nInd
< aUsersData
.getLength(); nInd
++ )
225 if ( aUsersData
[nInd
].getLength() != SHARED_ENTRYSIZE
)
226 throw lang::IllegalArgumentException();
228 for ( sal_Int32 nEntryInd
= 0; nEntryInd
< SHARED_ENTRYSIZE
; nEntryInd
++ )
230 aBuffer
.append( EscapeCharacters( aUsersData
[nInd
][nEntryInd
] ) );
231 if ( nEntryInd
< SHARED_ENTRYSIZE
- 1 )
232 aBuffer
.append( (sal_Unicode
)',' );
234 aBuffer
.append( (sal_Unicode
)';' );
238 ::rtl::OString
aStringData( ::rtl::OUStringToOString( aBuffer
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
) );
239 uno::Sequence
< sal_Int8
> aData( (sal_Int8
*)aStringData
.getStr(), aStringData
.getLength() );
240 m_xOutputStream
->writeBytes( aData
);
241 m_aUsersData
= aUsersData
;
244 // ----------------------------------------------------------------------
245 uno::Sequence
< ::rtl::OUString
> ShareControlFile::InsertOwnEntry()
247 ::osl::MutexGuard
aGuard( m_aMutex
);
250 throw io::NotConnectedException();
253 uno::Sequence
< ::uno::Sequence
< ::rtl::OUString
> > aNewData( m_aUsersData
.getLength() + 1 );
254 uno::Sequence
< ::rtl::OUString
> aNewEntry
= GenerateOwnEntry();
256 sal_Bool bExists
= sal_False
;
257 sal_Int32 nNewInd
= 0;
258 for ( sal_Int32 nInd
= 0; nInd
< m_aUsersData
.getLength(); nInd
++ )
260 if ( m_aUsersData
[nInd
].getLength() == SHARED_ENTRYSIZE
)
262 if ( m_aUsersData
[nInd
][SHARED_LOCALHOST_ID
] == aNewEntry
[SHARED_LOCALHOST_ID
]
263 && m_aUsersData
[nInd
][SHARED_SYSUSERNAME_ID
] == aNewEntry
[SHARED_SYSUSERNAME_ID
]
264 && m_aUsersData
[nInd
][SHARED_USERURL_ID
] == aNewEntry
[SHARED_USERURL_ID
] )
268 aNewData
[nNewInd
] = aNewEntry
;
274 aNewData
[nNewInd
] = m_aUsersData
[nInd
];
282 aNewData
[nNewInd
++] = aNewEntry
;
284 aNewData
.realloc( nNewInd
);
285 SetUsersDataAndStore( aNewData
);
290 // ----------------------------------------------------------------------
291 bool ShareControlFile::HasOwnEntry()
293 ::osl::MutexGuard
aGuard( m_aMutex
);
297 throw io::NotConnectedException();
301 uno::Sequence
< ::rtl::OUString
> aEntry
= GenerateOwnEntry();
303 for ( sal_Int32 nInd
= 0; nInd
< m_aUsersData
.getLength(); ++nInd
)
305 if ( m_aUsersData
[nInd
].getLength() == SHARED_ENTRYSIZE
&&
306 m_aUsersData
[nInd
][SHARED_LOCALHOST_ID
] == aEntry
[SHARED_LOCALHOST_ID
] &&
307 m_aUsersData
[nInd
][SHARED_SYSUSERNAME_ID
] == aEntry
[SHARED_SYSUSERNAME_ID
] &&
308 m_aUsersData
[nInd
][SHARED_USERURL_ID
] == aEntry
[SHARED_USERURL_ID
] )
317 // ----------------------------------------------------------------------
318 void ShareControlFile::RemoveEntry( const uno::Sequence
< ::rtl::OUString
>& aArgEntry
)
320 ::osl::MutexGuard
aGuard( m_aMutex
);
323 throw io::NotConnectedException();
327 uno::Sequence
< ::rtl::OUString
> aEntry
= aArgEntry
;
328 if ( aEntry
.getLength() != SHARED_ENTRYSIZE
)
329 aEntry
= GenerateOwnEntry();
331 uno::Sequence
< ::uno::Sequence
< ::rtl::OUString
> > aNewData( m_aUsersData
.getLength() + 1 );
333 sal_Int32 nNewInd
= 0;
334 for ( sal_Int32 nInd
= 0; nInd
< m_aUsersData
.getLength(); nInd
++ )
336 if ( m_aUsersData
[nInd
].getLength() == SHARED_ENTRYSIZE
)
338 if ( m_aUsersData
[nInd
][SHARED_LOCALHOST_ID
] != aEntry
[SHARED_LOCALHOST_ID
]
339 || m_aUsersData
[nInd
][SHARED_SYSUSERNAME_ID
] != aEntry
[SHARED_SYSUSERNAME_ID
]
340 || m_aUsersData
[nInd
][SHARED_USERURL_ID
] != aEntry
[SHARED_USERURL_ID
] )
342 aNewData
[nNewInd
] = m_aUsersData
[nInd
];
348 aNewData
.realloc( nNewInd
);
349 SetUsersDataAndStore( aNewData
);
353 // try to remove the file if it is empty
358 // ----------------------------------------------------------------------
359 void ShareControlFile::RemoveFile()
361 ::osl::MutexGuard
aGuard( m_aMutex
);
364 throw io::NotConnectedException();
368 uno::Reference
< lang::XMultiServiceFactory
> xFactory
= ::comphelper::getProcessServiceFactory();
369 uno::Reference
< ::com::sun::star::ucb::XSimpleFileAccess
> xSimpleFileAccess(
370 xFactory
->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess") ),
371 uno::UNO_QUERY_THROW
);
372 xSimpleFileAccess
->kill( m_aURL
);