1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svl.hxx"
26
27 #include <stdio.h>
28
29 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
30 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
31 #include <com/sun/star/ucb/XContent.hpp>
32 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
33 #include <com/sun/star/ucb/InteractiveIOException.hpp>
34 #include <com/sun/star/io/WrongFormatException.hpp>
35
36 #include <osl/time.h>
37 #include <osl/security.hxx>
38 #include <osl/socket.hxx>
39
40 #include <rtl/string.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <rtl/ustrbuf.hxx>
44
45 #include <comphelper/processfactory.hxx>
46 #include <ucbhelper/content.hxx>
47
48 #include <tools/urlobj.hxx>
49 #include <tools/stream.hxx>
50 #include <unotools/bootstrap.hxx>
51 #include <unotools/streamwrap.hxx>
52
53 #include <unotools/useroptions.hxx>
54
55 #include <svl/sharecontrolfile.hxx>
56
57 using namespace ::com::sun::star;
58
59 namespace svt {
60
61 // ----------------------------------------------------------------------
ShareControlFile(const::rtl::OUString & aOrigURL,const uno::Reference<lang::XMultiServiceFactory> & xFactory)62 ShareControlFile::ShareControlFile( const ::rtl::OUString& aOrigURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory )
63 : LockFileCommon( aOrigURL, xFactory, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".~sharing." ) ) )
64 {
65 OpenStream();
66
67 if ( !IsValid() )
68 throw io::NotConnectedException();
69 }
70
71 // ----------------------------------------------------------------------
~ShareControlFile()72 ShareControlFile::~ShareControlFile()
73 {
74 try
75 {
76 Close();
77 }
78 catch( uno::Exception& )
79 {}
80 }
81
82 // ----------------------------------------------------------------------
OpenStream()83 void ShareControlFile::OpenStream()
84 {
85 // if it is called outside of constructor the mutex must be locked already
86
87 if ( !m_xStream.is() && m_aURL.getLength() )
88 {
89 uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
90 ::ucbhelper::Content aContent = ::ucbhelper::Content( m_aURL, xDummyEnv );
91
92 uno::Reference< ucb::XContentIdentifier > xContId( aContent.get().is() ? aContent.get()->getIdentifier() : 0 );
93 if ( !xContId.is() || !xContId->getContentProviderScheme().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "file" ) ) ) )
94 throw io::IOException(); // the implementation supports only local files for now
95
96 uno::Reference< io::XStream > xStream;
97
98 // Currently the locking of the original document is intended to be used.
99 // 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.
100 // TODO/LATER: should the own file locking be used?
101
102 try
103 {
104 xStream = aContent.openWriteableStreamNoLock();
105 }
106 catch ( ucb::InteractiveIOException const & e )
107 {
108 if ( e.Code == ucb::IOErrorCode_NOT_EXISTING )
109 {
110 // Create file...
111 SvMemoryStream aStream(0,0);
112 uno::Reference< io::XInputStream > xInput( new ::utl::OInputStreamWrapper( aStream ) );
113 ucb::InsertCommandArgument aInsertArg;
114 aInsertArg.Data = xInput;
115 aInsertArg.ReplaceExisting = sal_False;
116 aContent.executeCommand( rtl::OUString::createFromAscii( "insert" ), uno::makeAny( aInsertArg ) );
117
118 // try to let the file be hidden if possible
119 try {
120 aContent.setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ), uno::makeAny( sal_True ) );
121 } catch( uno::Exception& ) {}
122
123 // Try to open one more time
124 xStream = aContent.openWriteableStreamNoLock();
125 }
126 else
127 throw;
128 }
129
130 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
131 m_xInputStream.set( xStream->getInputStream(), uno::UNO_QUERY_THROW );
132 m_xOutputStream.set( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
133 m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY_THROW );
134 m_xStream = xStream;
135 }
136 }
137
138 // ----------------------------------------------------------------------
Close()139 void ShareControlFile::Close()
140 {
141 // if it is called outside of destructor the mutex must be locked
142
143 if ( m_xStream.is() )
144 {
145 try
146 {
147 if ( m_xInputStream.is() )
148 m_xInputStream->closeInput();
149 if ( m_xOutputStream.is() )
150 m_xOutputStream->closeOutput();
151 }
152 catch( uno::Exception& )
153 {}
154
155 m_xStream = uno::Reference< io::XStream >();
156 m_xInputStream = uno::Reference< io::XInputStream >();
157 m_xOutputStream = uno::Reference< io::XOutputStream >();
158 m_xSeekable = uno::Reference< io::XSeekable >();
159 m_xTruncate = uno::Reference< io::XTruncate >();
160 m_aUsersData.realloc( 0 );
161 }
162 }
163
164 // ----------------------------------------------------------------------
GetUsersData()165 uno::Sequence< uno::Sequence< ::rtl::OUString > > ShareControlFile::GetUsersData()
166 {
167 ::osl::MutexGuard aGuard( m_aMutex );
168
169 if ( !IsValid() )
170 throw io::NotConnectedException();
171
172 if ( !m_aUsersData.getLength() )
173 {
174 sal_Int64 nLength = m_xSeekable->getLength();
175 if ( nLength > SAL_MAX_INT32 )
176 throw uno::RuntimeException();
177
178 uno::Sequence< sal_Int8 > aBuffer( (sal_Int32)nLength );
179 m_xSeekable->seek( 0 );
180
181 sal_Int32 nRead = m_xInputStream->readBytes( aBuffer, (sal_Int32)nLength );
182 nLength -= nRead;
183 while ( nLength > 0 )
184 {
185 uno::Sequence< sal_Int8 > aTmpBuf( (sal_Int32)nLength );
186 nRead = m_xInputStream->readBytes( aTmpBuf, (sal_Int32)nLength );
187 if ( nRead > nLength )
188 throw uno::RuntimeException();
189
190 for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
191 aBuffer[aBuffer.getLength() - (sal_Int32)nLength + nInd] = aTmpBuf[nInd];
192 nLength -= nRead;
193 }
194
195 m_aUsersData = ParseList( aBuffer );
196 }
197
198 return m_aUsersData;
199 }
200
201 // ----------------------------------------------------------------------
SetUsersDataAndStore(const uno::Sequence<uno::Sequence<::rtl::OUString>> & aUsersData)202 void ShareControlFile::SetUsersDataAndStore( const uno::Sequence< uno::Sequence< ::rtl::OUString > >& aUsersData )
203 {
204 ::osl::MutexGuard aGuard( m_aMutex );
205
206 if ( !IsValid() )
207 throw io::NotConnectedException();
208
209 if ( !m_xTruncate.is() || !m_xOutputStream.is() || !m_xSeekable.is() )
210 throw uno::RuntimeException();
211
212 m_xTruncate->truncate();
213 m_xSeekable->seek( 0 );
214
215 ::rtl::OUStringBuffer aBuffer;
216 for ( sal_Int32 nInd = 0; nInd < aUsersData.getLength(); nInd++ )
217 {
218 if ( aUsersData[nInd].getLength() != SHARED_ENTRYSIZE )
219 throw lang::IllegalArgumentException();
220
221 for ( sal_Int32 nEntryInd = 0; nEntryInd < SHARED_ENTRYSIZE; nEntryInd++ )
222 {
223 aBuffer.append( EscapeCharacters( aUsersData[nInd][nEntryInd] ) );
224 if ( nEntryInd < SHARED_ENTRYSIZE - 1 )
225 aBuffer.append( (sal_Unicode)',' );
226 else
227 aBuffer.append( (sal_Unicode)';' );
228 }
229 }
230
231 ::rtl::OString aStringData( ::rtl::OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) );
232 uno::Sequence< sal_Int8 > aData( (sal_Int8*)aStringData.getStr(), aStringData.getLength() );
233 m_xOutputStream->writeBytes( aData );
234 m_aUsersData = aUsersData;
235 }
236
237 // ----------------------------------------------------------------------
InsertOwnEntry()238 uno::Sequence< ::rtl::OUString > ShareControlFile::InsertOwnEntry()
239 {
240 ::osl::MutexGuard aGuard( m_aMutex );
241
242 if ( !IsValid() )
243 throw io::NotConnectedException();
244
245 GetUsersData();
246 uno::Sequence< ::uno::Sequence< ::rtl::OUString > > aNewData( m_aUsersData.getLength() + 1 );
247 uno::Sequence< ::rtl::OUString > aNewEntry = GenerateOwnEntry();
248
249 sal_Bool bExists = sal_False;
250 sal_Int32 nNewInd = 0;
251 for ( sal_Int32 nInd = 0; nInd < m_aUsersData.getLength(); nInd++ )
252 {
253 if ( m_aUsersData[nInd].getLength() == SHARED_ENTRYSIZE )
254 {
255 if ( m_aUsersData[nInd][SHARED_LOCALHOST_ID] == aNewEntry[SHARED_LOCALHOST_ID]
256 && m_aUsersData[nInd][SHARED_SYSUSERNAME_ID] == aNewEntry[SHARED_SYSUSERNAME_ID]
257 && m_aUsersData[nInd][SHARED_USERURL_ID] == aNewEntry[SHARED_USERURL_ID] )
258 {
259 if ( !bExists )
260 {
261 aNewData[nNewInd] = aNewEntry;
262 bExists = sal_True;
263 }
264 }
265 else
266 {
267 aNewData[nNewInd] = m_aUsersData[nInd];
268 }
269
270 nNewInd++;
271 }
272 }
273
274 if ( !bExists )
275 aNewData[nNewInd++] = aNewEntry;
276
277 aNewData.realloc( nNewInd );
278 SetUsersDataAndStore( aNewData );
279
280 return aNewEntry;
281 }
282
283 // ----------------------------------------------------------------------
HasOwnEntry()284 bool ShareControlFile::HasOwnEntry()
285 {
286 ::osl::MutexGuard aGuard( m_aMutex );
287
288 if ( !IsValid() )
289 {
290 throw io::NotConnectedException();
291 }
292
293 GetUsersData();
294 uno::Sequence< ::rtl::OUString > aEntry = GenerateOwnEntry();
295
296 for ( sal_Int32 nInd = 0; nInd < m_aUsersData.getLength(); ++nInd )
297 {
298 if ( m_aUsersData[nInd].getLength() == SHARED_ENTRYSIZE &&
299 m_aUsersData[nInd][SHARED_LOCALHOST_ID] == aEntry[SHARED_LOCALHOST_ID] &&
300 m_aUsersData[nInd][SHARED_SYSUSERNAME_ID] == aEntry[SHARED_SYSUSERNAME_ID] &&
301 m_aUsersData[nInd][SHARED_USERURL_ID] == aEntry[SHARED_USERURL_ID] )
302 {
303 return true;
304 }
305 }
306
307 return false;
308 }
309
310 // ----------------------------------------------------------------------
RemoveEntry(const uno::Sequence<::rtl::OUString> & aArgEntry)311 void ShareControlFile::RemoveEntry( const uno::Sequence< ::rtl::OUString >& aArgEntry )
312 {
313 ::osl::MutexGuard aGuard( m_aMutex );
314
315 if ( !IsValid() )
316 throw io::NotConnectedException();
317
318 GetUsersData();
319
320 uno::Sequence< ::rtl::OUString > aEntry = aArgEntry;
321 if ( aEntry.getLength() != SHARED_ENTRYSIZE )
322 aEntry = GenerateOwnEntry();
323
324 uno::Sequence< ::uno::Sequence< ::rtl::OUString > > aNewData( m_aUsersData.getLength() + 1 );
325
326 sal_Int32 nNewInd = 0;
327 for ( sal_Int32 nInd = 0; nInd < m_aUsersData.getLength(); nInd++ )
328 {
329 if ( m_aUsersData[nInd].getLength() == SHARED_ENTRYSIZE )
330 {
331 if ( m_aUsersData[nInd][SHARED_LOCALHOST_ID] != aEntry[SHARED_LOCALHOST_ID]
332 || m_aUsersData[nInd][SHARED_SYSUSERNAME_ID] != aEntry[SHARED_SYSUSERNAME_ID]
333 || m_aUsersData[nInd][SHARED_USERURL_ID] != aEntry[SHARED_USERURL_ID] )
334 {
335 aNewData[nNewInd] = m_aUsersData[nInd];
336 nNewInd++;
337 }
338 }
339 }
340
341 aNewData.realloc( nNewInd );
342 SetUsersDataAndStore( aNewData );
343
344 if ( !nNewInd )
345 {
346 // try to remove the file if it is empty
347 RemoveFile();
348 }
349 }
350
351 // ----------------------------------------------------------------------
RemoveFile()352 void ShareControlFile::RemoveFile()
353 {
354 ::osl::MutexGuard aGuard( m_aMutex );
355
356 if ( !IsValid() )
357 throw io::NotConnectedException();
358
359 Close();
360
361 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
362 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleFileAccess(
363 xFactory->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess") ),
364 uno::UNO_QUERY_THROW );
365 xSimpleFileAccess->kill( m_aURL );
366 }
367
368 } // namespace svt
369
370