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