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 <com/sun/star/ucb/SimpleFileAccess.hpp>
22 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
23 : #include <com/sun/star/ucb/XContent.hpp>
24 : #include <com/sun/star/ucb/InsertCommandArgument.hpp>
25 : #include <com/sun/star/ucb/InteractiveIOException.hpp>
26 : #include <com/sun/star/io/WrongFormatException.hpp>
27 :
28 : #include <osl/time.h>
29 : #include <osl/security.hxx>
30 : #include <osl/socket.hxx>
31 : #include <o3tl/enumrange.hxx>
32 :
33 : #include <rtl/string.hxx>
34 : #include <rtl/ustring.hxx>
35 : #include <rtl/strbuf.hxx>
36 : #include <rtl/ustrbuf.hxx>
37 :
38 : #include <comphelper/processfactory.hxx>
39 : #include <ucbhelper/content.hxx>
40 :
41 : #include <tools/stream.hxx>
42 : #include <unotools/bootstrap.hxx>
43 : #include <unotools/streamwrap.hxx>
44 :
45 : #include <unotools/useroptions.hxx>
46 :
47 : #include <svl/sharecontrolfile.hxx>
48 :
49 : using namespace ::com::sun::star;
50 :
51 : namespace svt {
52 :
53 :
54 0 : ShareControlFile::ShareControlFile( const OUString& aOrigURL )
55 0 : : LockFileCommon( aOrigURL, OUString( ".~sharing." ) )
56 : {
57 0 : OpenStream();
58 :
59 0 : if ( !IsValid() )
60 0 : throw io::NotConnectedException();
61 0 : }
62 :
63 :
64 0 : ShareControlFile::~ShareControlFile()
65 : {
66 : try
67 : {
68 0 : Close();
69 : }
70 0 : catch( uno::Exception& )
71 : {}
72 0 : }
73 :
74 :
75 0 : void ShareControlFile::OpenStream()
76 : {
77 : // if it is called outside of constructor the mutex must be locked already
78 :
79 0 : if ( !m_xStream.is() && !m_aURL.isEmpty() )
80 : {
81 0 : uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
82 0 : ::ucbhelper::Content aContent = ::ucbhelper::Content( m_aURL, xDummyEnv, comphelper::getProcessComponentContext() );
83 :
84 0 : uno::Reference< ucb::XContentIdentifier > xContId( aContent.get().is() ? aContent.get()->getIdentifier() : 0 );
85 0 : if ( !xContId.is() || xContId->getContentProviderScheme() != "file" )
86 0 : throw io::IOException(); // the implementation supports only local files for now
87 :
88 0 : uno::Reference< io::XStream > xStream;
89 :
90 : // Currently the locking of the original document is intended to be used.
91 : // 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.
92 : // TODO/LATER: should the own file locking be used?
93 :
94 : try
95 : {
96 0 : xStream = aContent.openWriteableStreamNoLock();
97 : }
98 0 : catch ( ucb::InteractiveIOException const & e )
99 : {
100 0 : if ( e.Code == ucb::IOErrorCode_NOT_EXISTING )
101 : {
102 : // Create file...
103 0 : SvMemoryStream aStream(0,0);
104 0 : uno::Reference< io::XInputStream > xInput( new ::utl::OInputStreamWrapper( aStream ) );
105 0 : ucb::InsertCommandArgument aInsertArg;
106 0 : aInsertArg.Data = xInput;
107 0 : aInsertArg.ReplaceExisting = sal_False;
108 0 : aContent.executeCommand( OUString("insert"), uno::makeAny( aInsertArg ) );
109 :
110 : // try to let the file be hidden if possible
111 : try {
112 0 : aContent.setPropertyValue("IsHidden", uno::makeAny( sal_True ) );
113 0 : } catch( uno::Exception& ) {}
114 :
115 : // Try to open one more time
116 0 : xStream = aContent.openWriteableStreamNoLock();
117 : }
118 : else
119 0 : throw;
120 : }
121 :
122 0 : m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
123 0 : m_xInputStream.set( xStream->getInputStream(), uno::UNO_QUERY_THROW );
124 0 : m_xOutputStream.set( xStream->getOutputStream(), uno::UNO_QUERY_THROW );
125 0 : m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY_THROW );
126 0 : m_xStream = xStream;
127 : }
128 0 : }
129 :
130 :
131 0 : void ShareControlFile::Close()
132 : {
133 : // if it is called outside of destructor the mutex must be locked
134 :
135 0 : if ( m_xStream.is() )
136 : {
137 : try
138 : {
139 0 : if ( m_xInputStream.is() )
140 0 : m_xInputStream->closeInput();
141 0 : if ( m_xOutputStream.is() )
142 0 : m_xOutputStream->closeOutput();
143 : }
144 0 : catch( uno::Exception& )
145 : {}
146 :
147 0 : m_xStream = uno::Reference< io::XStream >();
148 0 : m_xInputStream = uno::Reference< io::XInputStream >();
149 0 : m_xOutputStream = uno::Reference< io::XOutputStream >();
150 0 : m_xSeekable = uno::Reference< io::XSeekable >();
151 0 : m_xTruncate = uno::Reference< io::XTruncate >();
152 0 : m_aUsersData.clear();
153 : }
154 0 : }
155 :
156 :
157 0 : std::vector< o3tl::enumarray< LockFileComponent, OUString > > ShareControlFile::GetUsersData()
158 : {
159 0 : ::osl::MutexGuard aGuard( m_aMutex );
160 :
161 0 : if ( !IsValid() )
162 0 : throw io::NotConnectedException();
163 :
164 0 : if ( m_aUsersData.empty() )
165 : {
166 0 : sal_Int64 nLength = m_xSeekable->getLength();
167 0 : if ( nLength > SAL_MAX_INT32 )
168 0 : throw uno::RuntimeException();
169 :
170 0 : uno::Sequence< sal_Int8 > aBuffer( (sal_Int32)nLength );
171 0 : m_xSeekable->seek( 0 );
172 :
173 0 : sal_Int32 nRead = m_xInputStream->readBytes( aBuffer, (sal_Int32)nLength );
174 0 : nLength -= nRead;
175 0 : while ( nLength > 0 )
176 : {
177 0 : uno::Sequence< sal_Int8 > aTmpBuf( (sal_Int32)nLength );
178 0 : nRead = m_xInputStream->readBytes( aTmpBuf, (sal_Int32)nLength );
179 0 : if ( nRead > nLength )
180 0 : throw uno::RuntimeException();
181 :
182 0 : for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
183 0 : aBuffer[aBuffer.getLength() - (sal_Int32)nLength + nInd] = aTmpBuf[nInd];
184 0 : nLength -= nRead;
185 0 : }
186 :
187 0 : ParseList( aBuffer, m_aUsersData );
188 : }
189 :
190 0 : return m_aUsersData;
191 : }
192 :
193 :
194 0 : void ShareControlFile::SetUsersDataAndStore( const std::vector< LockFileEntry >& aUsersData )
195 : {
196 0 : ::osl::MutexGuard aGuard( m_aMutex );
197 :
198 0 : if ( !IsValid() )
199 0 : throw io::NotConnectedException();
200 :
201 0 : if ( !m_xTruncate.is() || !m_xOutputStream.is() || !m_xSeekable.is() )
202 0 : throw uno::RuntimeException();
203 :
204 0 : m_xTruncate->truncate();
205 0 : m_xSeekable->seek( 0 );
206 :
207 0 : OUStringBuffer aBuffer;
208 0 : for ( size_t nInd = 0; nInd < aUsersData.size(); nInd++ )
209 : {
210 0 : for ( LockFileComponent nEntryInd : o3tl::enumrange<LockFileComponent>() )
211 : {
212 0 : aBuffer.append( EscapeCharacters( aUsersData[nInd][nEntryInd] ) );
213 0 : if ( nEntryInd < LockFileComponent::LAST )
214 0 : aBuffer.append( ',' );
215 : else
216 0 : aBuffer.append( ';' );
217 : }
218 : }
219 :
220 0 : OString aStringData( OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) );
221 0 : uno::Sequence< sal_Int8 > aData( reinterpret_cast<sal_Int8 const *>(aStringData.getStr()), aStringData.getLength() );
222 0 : m_xOutputStream->writeBytes( aData );
223 0 : m_aUsersData = aUsersData;
224 0 : }
225 :
226 :
227 0 : LockFileEntry ShareControlFile::InsertOwnEntry()
228 : {
229 0 : ::osl::MutexGuard aGuard( m_aMutex );
230 :
231 0 : if ( !IsValid() )
232 0 : throw io::NotConnectedException();
233 :
234 0 : GetUsersData();
235 0 : std::vector< LockFileEntry > aNewData( m_aUsersData );
236 0 : LockFileEntry aNewEntry = GenerateOwnEntry();
237 :
238 0 : bool bExists = false;
239 0 : sal_Int32 nNewInd = 0;
240 0 : for ( size_t nInd = 0; nInd < m_aUsersData.size(); nInd++ )
241 : {
242 0 : if ( m_aUsersData[nInd][LockFileComponent::LOCALHOST] == aNewEntry[LockFileComponent::LOCALHOST]
243 0 : && m_aUsersData[nInd][LockFileComponent::SYSUSERNAME] == aNewEntry[LockFileComponent::SYSUSERNAME]
244 0 : && m_aUsersData[nInd][LockFileComponent::USERURL] == aNewEntry[LockFileComponent::USERURL] )
245 : {
246 0 : if ( !bExists )
247 : {
248 0 : aNewData[nNewInd] = aNewEntry;
249 0 : bExists = true;
250 : }
251 : }
252 : else
253 : {
254 0 : aNewData[nNewInd] = m_aUsersData[nInd];
255 : }
256 :
257 0 : nNewInd++;
258 : }
259 :
260 0 : if ( !bExists )
261 0 : aNewData.push_back( aNewEntry );
262 :
263 0 : SetUsersDataAndStore( aNewData );
264 :
265 0 : return aNewEntry;
266 : }
267 :
268 :
269 0 : bool ShareControlFile::HasOwnEntry()
270 : {
271 0 : ::osl::MutexGuard aGuard( m_aMutex );
272 :
273 0 : if ( !IsValid() )
274 : {
275 0 : throw io::NotConnectedException();
276 : }
277 :
278 0 : GetUsersData();
279 0 : LockFileEntry aEntry = GenerateOwnEntry();
280 :
281 0 : for ( size_t nInd = 0; nInd < m_aUsersData.size(); ++nInd )
282 : {
283 0 : if ( m_aUsersData[nInd][LockFileComponent::LOCALHOST] == aEntry[LockFileComponent::LOCALHOST] &&
284 0 : m_aUsersData[nInd][LockFileComponent::SYSUSERNAME] == aEntry[LockFileComponent::SYSUSERNAME] &&
285 0 : m_aUsersData[nInd][LockFileComponent::USERURL] == aEntry[LockFileComponent::USERURL] )
286 : {
287 0 : return true;
288 : }
289 : }
290 :
291 0 : return false;
292 : }
293 :
294 :
295 0 : void ShareControlFile::RemoveEntry()
296 : {
297 0 : RemoveEntry(GenerateOwnEntry());
298 0 : }
299 :
300 0 : void ShareControlFile::RemoveEntry( const LockFileEntry& aEntry )
301 : {
302 0 : ::osl::MutexGuard aGuard( m_aMutex );
303 :
304 0 : if ( !IsValid() )
305 0 : throw io::NotConnectedException();
306 :
307 0 : GetUsersData();
308 :
309 0 : std::vector< LockFileEntry > aNewData;
310 :
311 0 : for ( size_t nInd = 0; nInd < m_aUsersData.size(); nInd++ )
312 : {
313 0 : if ( m_aUsersData[nInd][LockFileComponent::LOCALHOST] != aEntry[LockFileComponent::LOCALHOST]
314 0 : || m_aUsersData[nInd][LockFileComponent::SYSUSERNAME] != aEntry[LockFileComponent::SYSUSERNAME]
315 0 : || m_aUsersData[nInd][LockFileComponent::USERURL] != aEntry[LockFileComponent::USERURL] )
316 : {
317 0 : aNewData.push_back( m_aUsersData[nInd] );
318 : }
319 : }
320 :
321 0 : SetUsersDataAndStore( aNewData );
322 :
323 0 : if ( aNewData.empty() )
324 : {
325 : // try to remove the file if it is empty
326 0 : RemoveFile();
327 0 : }
328 0 : }
329 :
330 :
331 0 : void ShareControlFile::RemoveFile()
332 : {
333 0 : ::osl::MutexGuard aGuard( m_aMutex );
334 :
335 0 : if ( !IsValid() )
336 0 : throw io::NotConnectedException();
337 :
338 0 : Close();
339 :
340 0 : uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
341 0 : xSimpleFileAccess->kill( m_aURL );
342 0 : }
343 :
344 : } // namespace svt
345 :
346 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|