1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
29 #include <osl/security.hxx>
30 #include <osl/socket.hxx>
31 #include <o3tl/enumrange.hxx>
33 #include <rtl/string.hxx>
34 #include <rtl/ustring.hxx>
35 #include <rtl/strbuf.hxx>
36 #include <rtl/ustrbuf.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <ucbhelper/content.hxx>
41 #include <tools/stream.hxx>
42 #include <unotools/bootstrap.hxx>
43 #include <unotools/streamwrap.hxx>
45 #include <unotools/useroptions.hxx>
47 #include <svl/sharecontrolfile.hxx>
49 using namespace ::com::sun::star
;
54 ShareControlFile::ShareControlFile( const OUString
& aOrigURL
)
55 : LockFileCommon( aOrigURL
, OUString( ".~sharing." ) )
60 throw io::NotConnectedException();
64 ShareControlFile::~ShareControlFile()
70 catch( uno::Exception
& )
75 void ShareControlFile::OpenStream()
77 // if it is called outside of constructor the mutex must be locked already
79 if ( !m_xStream
.is() && !m_aURL
.isEmpty() )
81 uno::Reference
< ucb::XCommandEnvironment
> xDummyEnv
;
82 ::ucbhelper::Content aContent
= ::ucbhelper::Content( m_aURL
, xDummyEnv
, comphelper::getProcessComponentContext() );
84 uno::Reference
< ucb::XContentIdentifier
> xContId( aContent
.get().is() ? aContent
.get()->getIdentifier() : 0 );
85 if ( !xContId
.is() || xContId
->getContentProviderScheme() != "file" )
86 throw io::IOException(); // the implementation supports only local files for now
88 uno::Reference
< io::XStream
> xStream
;
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?
96 xStream
= aContent
.openWriteableStreamNoLock();
98 catch ( ucb::InteractiveIOException
const & e
)
100 if ( e
.Code
== ucb::IOErrorCode_NOT_EXISTING
)
103 SvMemoryStream
aStream(0,0);
104 uno::Reference
< io::XInputStream
> xInput( new ::utl::OInputStreamWrapper( aStream
) );
105 ucb::InsertCommandArgument aInsertArg
;
106 aInsertArg
.Data
= xInput
;
107 aInsertArg
.ReplaceExisting
= sal_False
;
108 aContent
.executeCommand( OUString("insert"), uno::makeAny( aInsertArg
) );
110 // try to let the file be hidden if possible
112 aContent
.setPropertyValue("IsHidden", uno::makeAny( sal_True
) );
113 } catch( uno::Exception
& ) {}
115 // Try to open one more time
116 xStream
= aContent
.openWriteableStreamNoLock();
122 m_xSeekable
.set( xStream
, uno::UNO_QUERY_THROW
);
123 m_xInputStream
.set( xStream
->getInputStream(), uno::UNO_QUERY_THROW
);
124 m_xOutputStream
.set( xStream
->getOutputStream(), uno::UNO_QUERY_THROW
);
125 m_xTruncate
.set( m_xOutputStream
, uno::UNO_QUERY_THROW
);
131 void ShareControlFile::Close()
133 // if it is called outside of destructor the mutex must be locked
135 if ( m_xStream
.is() )
139 if ( m_xInputStream
.is() )
140 m_xInputStream
->closeInput();
141 if ( m_xOutputStream
.is() )
142 m_xOutputStream
->closeOutput();
144 catch( uno::Exception
& )
147 m_xStream
= uno::Reference
< io::XStream
>();
148 m_xInputStream
= uno::Reference
< io::XInputStream
>();
149 m_xOutputStream
= uno::Reference
< io::XOutputStream
>();
150 m_xSeekable
= uno::Reference
< io::XSeekable
>();
151 m_xTruncate
= uno::Reference
< io::XTruncate
>();
152 m_aUsersData
.clear();
157 std::vector
< o3tl::enumarray
< LockFileComponent
, OUString
> > ShareControlFile::GetUsersData()
159 ::osl::MutexGuard
aGuard( m_aMutex
);
162 throw io::NotConnectedException();
164 if ( m_aUsersData
.empty() )
166 sal_Int64 nLength
= m_xSeekable
->getLength();
167 if ( nLength
> SAL_MAX_INT32
)
168 throw uno::RuntimeException();
170 uno::Sequence
< sal_Int8
> aBuffer( (sal_Int32
)nLength
);
171 m_xSeekable
->seek( 0 );
173 sal_Int32 nRead
= m_xInputStream
->readBytes( aBuffer
, (sal_Int32
)nLength
);
175 while ( nLength
> 0 )
177 uno::Sequence
< sal_Int8
> aTmpBuf( (sal_Int32
)nLength
);
178 nRead
= m_xInputStream
->readBytes( aTmpBuf
, (sal_Int32
)nLength
);
179 if ( nRead
> nLength
)
180 throw uno::RuntimeException();
182 for ( sal_Int32 nInd
= 0; nInd
< nRead
; nInd
++ )
183 aBuffer
[aBuffer
.getLength() - (sal_Int32
)nLength
+ nInd
] = aTmpBuf
[nInd
];
187 ParseList( aBuffer
, m_aUsersData
);
194 void ShareControlFile::SetUsersDataAndStore( const std::vector
< LockFileEntry
>& aUsersData
)
196 ::osl::MutexGuard
aGuard( m_aMutex
);
199 throw io::NotConnectedException();
201 if ( !m_xTruncate
.is() || !m_xOutputStream
.is() || !m_xSeekable
.is() )
202 throw uno::RuntimeException();
204 m_xTruncate
->truncate();
205 m_xSeekable
->seek( 0 );
207 OUStringBuffer aBuffer
;
208 for ( size_t nInd
= 0; nInd
< aUsersData
.size(); nInd
++ )
210 for ( LockFileComponent nEntryInd
: o3tl::enumrange
<LockFileComponent
>() )
212 aBuffer
.append( EscapeCharacters( aUsersData
[nInd
][nEntryInd
] ) );
213 if ( nEntryInd
< LockFileComponent::LAST
)
214 aBuffer
.append( ',' );
216 aBuffer
.append( ';' );
220 OString
aStringData( OUStringToOString( aBuffer
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
) );
221 uno::Sequence
< sal_Int8
> aData( reinterpret_cast<sal_Int8
const *>(aStringData
.getStr()), aStringData
.getLength() );
222 m_xOutputStream
->writeBytes( aData
);
223 m_aUsersData
= aUsersData
;
227 LockFileEntry
ShareControlFile::InsertOwnEntry()
229 ::osl::MutexGuard
aGuard( m_aMutex
);
232 throw io::NotConnectedException();
235 std::vector
< LockFileEntry
> aNewData( m_aUsersData
);
236 LockFileEntry aNewEntry
= GenerateOwnEntry();
238 bool bExists
= false;
239 sal_Int32 nNewInd
= 0;
240 for ( size_t nInd
= 0; nInd
< m_aUsersData
.size(); nInd
++ )
242 if ( m_aUsersData
[nInd
][LockFileComponent::LOCALHOST
] == aNewEntry
[LockFileComponent::LOCALHOST
]
243 && m_aUsersData
[nInd
][LockFileComponent::SYSUSERNAME
] == aNewEntry
[LockFileComponent::SYSUSERNAME
]
244 && m_aUsersData
[nInd
][LockFileComponent::USERURL
] == aNewEntry
[LockFileComponent::USERURL
] )
248 aNewData
[nNewInd
] = aNewEntry
;
254 aNewData
[nNewInd
] = m_aUsersData
[nInd
];
261 aNewData
.push_back( aNewEntry
);
263 SetUsersDataAndStore( aNewData
);
269 bool ShareControlFile::HasOwnEntry()
271 ::osl::MutexGuard
aGuard( m_aMutex
);
275 throw io::NotConnectedException();
279 LockFileEntry aEntry
= GenerateOwnEntry();
281 for ( size_t nInd
= 0; nInd
< m_aUsersData
.size(); ++nInd
)
283 if ( m_aUsersData
[nInd
][LockFileComponent::LOCALHOST
] == aEntry
[LockFileComponent::LOCALHOST
] &&
284 m_aUsersData
[nInd
][LockFileComponent::SYSUSERNAME
] == aEntry
[LockFileComponent::SYSUSERNAME
] &&
285 m_aUsersData
[nInd
][LockFileComponent::USERURL
] == aEntry
[LockFileComponent::USERURL
] )
295 void ShareControlFile::RemoveEntry()
297 RemoveEntry(GenerateOwnEntry());
300 void ShareControlFile::RemoveEntry( const LockFileEntry
& aEntry
)
302 ::osl::MutexGuard
aGuard( m_aMutex
);
305 throw io::NotConnectedException();
309 std::vector
< LockFileEntry
> aNewData
;
311 for ( size_t nInd
= 0; nInd
< m_aUsersData
.size(); nInd
++ )
313 if ( m_aUsersData
[nInd
][LockFileComponent::LOCALHOST
] != aEntry
[LockFileComponent::LOCALHOST
]
314 || m_aUsersData
[nInd
][LockFileComponent::SYSUSERNAME
] != aEntry
[LockFileComponent::SYSUSERNAME
]
315 || m_aUsersData
[nInd
][LockFileComponent::USERURL
] != aEntry
[LockFileComponent::USERURL
] )
317 aNewData
.push_back( m_aUsersData
[nInd
] );
321 SetUsersDataAndStore( aNewData
);
323 if ( aNewData
.empty() )
325 // try to remove the file if it is empty
331 void ShareControlFile::RemoveFile()
333 ::osl::MutexGuard
aGuard( m_aMutex
);
336 throw io::NotConnectedException();
340 uno::Reference
<ucb::XSimpleFileAccess3
> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
341 xSimpleFileAccess
->kill( m_aURL
);
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */