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 :
10 : #include <cstdio>
11 :
12 : #include <com/sun/star/beans/PropertyAttribute.hpp>
13 : #include <com/sun/star/beans/PropertyValue.hpp>
14 : #include <com/sun/star/beans/PropertyValues.hpp>
15 : #include <com/sun/star/beans/XPropertySetInfo.hpp>
16 : #include <com/sun/star/document/CmisProperty.hpp>
17 : #include <com/sun/star/io/XActiveDataSink.hpp>
18 : #include <com/sun/star/io/XActiveDataStreamer.hpp>
19 : #include <com/sun/star/lang/IllegalAccessException.hpp>
20 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
21 : #include <com/sun/star/task/InteractionClassification.hpp>
22 : #include <com/sun/star/ucb/ContentInfo.hpp>
23 : #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
24 : #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
25 : #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
26 : #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
27 : #include <com/sun/star/ucb/MissingInputStreamException.hpp>
28 : #include <com/sun/star/ucb/NameClash.hpp>
29 : #include <com/sun/star/ucb/NameClashException.hpp>
30 : #include <com/sun/star/ucb/OpenMode.hpp>
31 : #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
32 : #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
33 : #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
34 : #include <com/sun/star/ucb/XCommandInfo.hpp>
35 : #include <com/sun/star/ucb/XDynamicResultSet.hpp>
36 : #ifndef SYSTEM_CURL
37 : #include <com/sun/star/xml/crypto/XDigestContext.hpp>
38 : #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp>
39 : #include <com/sun/star/xml/crypto/DigestID.hpp>
40 : #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
41 : #endif
42 :
43 : #include <comphelper/processfactory.hxx>
44 : #include <cppuhelper/exc_hlp.hxx>
45 : #include <config_oauth2.h>
46 : #include <ucbhelper/cancelcommandexecution.hxx>
47 : #include <ucbhelper/content.hxx>
48 : #include <ucbhelper/contentidentifier.hxx>
49 : #include <ucbhelper/std_inputstream.hxx>
50 : #include <ucbhelper/std_outputstream.hxx>
51 : #include <ucbhelper/propertyvalueset.hxx>
52 : #include <ucbhelper/proxydecider.hxx>
53 : #include <sax/tools/converter.hxx>
54 :
55 : #include "auth_provider.hxx"
56 : #include "certvalidation_handler.hxx"
57 : #include "cmis_content.hxx"
58 : #include "cmis_provider.hxx"
59 : #include "cmis_resultset.hxx"
60 : #include "cmis_strings.hxx"
61 :
62 : #define OUSTR_TO_STDSTR(s) string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
63 : #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
64 :
65 : using namespace com::sun::star;
66 : using namespace std;
67 :
68 : namespace
69 : {
70 0 : util::DateTime lcl_boostToUnoTime(const boost::posix_time::ptime& boostTime)
71 : {
72 0 : util::DateTime unoTime;
73 0 : unoTime.Year = boostTime.date().year();
74 0 : unoTime.Month = boostTime.date().month();
75 0 : unoTime.Day = boostTime.date().day();
76 0 : unoTime.Hours = boostTime.time_of_day().hours();
77 0 : unoTime.Minutes = boostTime.time_of_day().minutes();
78 0 : unoTime.Seconds = boostTime.time_of_day().seconds();
79 :
80 : // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
81 : // to actually get nanosecond precision in boostTime?
82 : // use this way rather than total_nanos to avoid overflows with 32-bit long
83 0 : const long ticks = boostTime.time_of_day().fractional_seconds();
84 0 : long nanoSeconds = ticks * ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
85 :
86 0 : unoTime.NanoSeconds = nanoSeconds;
87 :
88 0 : return unoTime;
89 : }
90 :
91 0 : uno::Any lcl_cmisPropertyToUno( libcmis::PropertyPtr pProperty )
92 : {
93 0 : uno::Any aValue;
94 0 : switch ( pProperty->getPropertyType( )->getType( ) )
95 : {
96 : default:
97 : case libcmis::PropertyType::String:
98 : {
99 0 : vector< string > aCmisStrings = pProperty->getStrings( );
100 0 : uno::Sequence< OUString > aStrings( aCmisStrings.size( ) );
101 0 : OUString* aStringsArr = aStrings.getArray( );
102 0 : sal_Int32 i = 0;
103 0 : for ( vector< string >::iterator it = aCmisStrings.begin( );
104 0 : it != aCmisStrings.end( ); ++it, ++i )
105 : {
106 0 : string str = *it;
107 0 : aStringsArr[i] = STD_TO_OUSTR( str );
108 0 : }
109 0 : aValue <<= aStrings;
110 : }
111 0 : break;
112 : case libcmis::PropertyType::Integer:
113 : {
114 0 : vector< long > aCmisLongs = pProperty->getLongs( );
115 0 : uno::Sequence< sal_Int64 > aLongs( aCmisLongs.size( ) );
116 0 : sal_Int64* aLongsArr = aLongs.getArray( );
117 0 : sal_Int32 i = 0;
118 0 : for ( vector< long >::iterator it = aCmisLongs.begin( );
119 0 : it != aCmisLongs.end( ); ++it, ++i )
120 : {
121 0 : aLongsArr[i] = *it;
122 : }
123 0 : aValue <<= aLongs;
124 : }
125 0 : break;
126 : case libcmis::PropertyType::Decimal:
127 : {
128 0 : vector< double > aCmisDoubles = pProperty->getDoubles( );
129 0 : uno::Sequence< double > aDoubles( aCmisDoubles.size( ) );
130 0 : double* aDoublesArr = aDoubles.getArray( );
131 0 : sal_Int32 i = 0;
132 0 : for ( vector< double >::iterator it = aCmisDoubles.begin( );
133 0 : it != aCmisDoubles.end( ); ++it, ++i )
134 : {
135 0 : aDoublesArr[i] = *it;
136 : }
137 0 : aValue <<= aDoubles;
138 : }
139 0 : break;
140 : case libcmis::PropertyType::Bool:
141 : {
142 0 : vector< bool > aCmisBools = pProperty->getBools( );
143 0 : uno::Sequence< sal_Bool > aBools( aCmisBools.size( ) );
144 0 : sal_Bool* aBoolsArr = aBools.getArray( );
145 0 : sal_Int32 i = 0;
146 0 : for ( vector< bool >::iterator it = aCmisBools.begin( );
147 0 : it != aCmisBools.end( ); ++it, ++i )
148 : {
149 0 : aBoolsArr[i] = *it;
150 : }
151 0 : aValue <<= aBools;
152 : }
153 0 : break;
154 : case libcmis::PropertyType::DateTime:
155 : {
156 0 : vector< boost::posix_time::ptime > aCmisTimes = pProperty->getDateTimes( );
157 0 : uno::Sequence< util::DateTime > aTimes( aCmisTimes.size( ) );
158 0 : util::DateTime* aTimesArr = aTimes.getArray( );
159 0 : sal_Int32 i = 0;
160 0 : for ( vector< boost::posix_time::ptime >::iterator it = aCmisTimes.begin( );
161 0 : it != aCmisTimes.end( ); ++it, ++i )
162 : {
163 0 : aTimesArr[i] = lcl_boostToUnoTime( *it );
164 : }
165 0 : aValue <<= aTimes;
166 : }
167 0 : break;
168 : }
169 0 : return aValue;
170 : }
171 :
172 0 : libcmis::PropertyPtr lcl_unoToCmisProperty(const document::CmisProperty& prop )
173 : {
174 0 : libcmis::PropertyTypePtr propertyType( new libcmis::PropertyType( ) );
175 :
176 0 : OUString id = prop.Id;
177 0 : OUString name = prop.Name;
178 0 : bool bUpdatable = prop.Updatable;
179 0 : bool bRequired = prop.Required;
180 0 : bool bMultiValued = prop.MultiValued;
181 0 : bool bOpenChoice = prop.OpenChoice;
182 0 : uno::Any value = prop.Value;
183 0 : std::vector< std::string > values;
184 :
185 0 : libcmis::PropertyType::Type type = libcmis::PropertyType::String;
186 0 : if ( prop.Type == CMIS_TYPE_STRING )
187 : {
188 0 : uno::Sequence< OUString > seqValue;
189 0 : value >>= seqValue;
190 0 : sal_Int32 m_nNumValue = seqValue.getLength( );
191 0 : for ( sal_Int32 i = 0; i < m_nNumValue; ++i )
192 : {
193 0 : values.push_back( OUSTR_TO_STDSTR( seqValue[i] ) );
194 : }
195 0 : type = libcmis::PropertyType::String;
196 : }
197 0 : else if ( prop.Type == CMIS_TYPE_BOOL )
198 : {
199 0 : uno::Sequence< sal_Bool > seqValue;
200 0 : value >>= seqValue;
201 0 : sal_Int32 m_nNumValue = seqValue.getLength( );
202 0 : for ( sal_Int32 i = 0; i < m_nNumValue; ++i )
203 : {
204 0 : values.push_back( OUSTR_TO_STDSTR( OUString::boolean( seqValue[i] ) ) );
205 : }
206 0 : type = libcmis::PropertyType::Bool;
207 : }
208 0 : else if ( prop.Type == CMIS_TYPE_INTEGER )
209 : {
210 0 : uno::Sequence< sal_Int64 > seqValue;
211 0 : value >>= seqValue;
212 0 : sal_Int32 m_nNumValue = seqValue.getLength( );
213 0 : for ( sal_Int32 i = 0; i < m_nNumValue; ++i )
214 : {
215 0 : values.push_back( OUSTR_TO_STDSTR( OUString::number( seqValue[i] ) ) );
216 : }
217 0 : type = libcmis::PropertyType::Integer;
218 : }
219 0 : else if ( prop.Type == CMIS_TYPE_DECIMAL )
220 : {
221 0 : uno::Sequence< double > seqValue;
222 0 : value >>= seqValue;
223 0 : sal_Int32 m_nNumValue = seqValue.getLength( );
224 0 : for ( sal_Int32 i = 0; i < m_nNumValue; ++i )
225 : {
226 0 : values.push_back( OUSTR_TO_STDSTR( OUString::number( seqValue[i] ) ) );
227 : }
228 0 : type = libcmis::PropertyType::Decimal;
229 : }
230 0 : else if ( prop.Type == CMIS_TYPE_DATETIME )
231 : {
232 0 : uno::Sequence< util::DateTime > seqValue;
233 0 : value >>= seqValue;
234 0 : sal_Int32 m_nNumValue = seqValue.getLength( );
235 0 : for ( sal_Int32 i = 0; i < m_nNumValue; ++i )
236 : {
237 0 : OUStringBuffer aBuffer;
238 0 : ::sax::Converter::convertDateTime( aBuffer, seqValue[i], 0, false );
239 0 : values.push_back( OUSTR_TO_STDSTR( aBuffer.makeStringAndClear( ) ) );
240 0 : }
241 0 : type = libcmis::PropertyType::DateTime;
242 : }
243 :
244 0 : propertyType->setId( OUSTR_TO_STDSTR( id ));
245 0 : propertyType->setDisplayName( OUSTR_TO_STDSTR( name ) );
246 0 : propertyType->setUpdatable( bUpdatable );
247 0 : propertyType->setRequired( bRequired );
248 0 : propertyType->setMultiValued( bMultiValued );
249 0 : propertyType->setOpenChoice( bOpenChoice );
250 0 : propertyType->setType( type );
251 :
252 0 : libcmis::PropertyPtr property( new libcmis::Property( propertyType, values ) );
253 :
254 0 : return property;
255 : }
256 : }
257 :
258 : namespace cmis
259 : {
260 0 : Content::Content( const uno::Reference< uno::XComponentContext >& rxContext,
261 : ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier,
262 : libcmis::ObjectPtr pObject )
263 : throw ( ucb::ContentCreationException )
264 : : ContentImplHelper( rxContext, pProvider, Identifier ),
265 : m_pProvider( pProvider ),
266 : m_pSession( NULL ),
267 : m_pObject( pObject ),
268 0 : m_sURL( Identifier->getContentIdentifier( ) ),
269 0 : m_aURL( Identifier->getContentIdentifier( ) ),
270 : m_bTransient( false ),
271 0 : m_bIsFolder( false )
272 : {
273 : SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL );
274 :
275 0 : m_sObjectPath = m_aURL.getObjectPath( );
276 0 : m_sObjectId = m_aURL.getObjectId( );
277 0 : }
278 :
279 0 : Content::Content( const uno::Reference< uno::XComponentContext >& rxContext, ContentProvider *pProvider,
280 : const uno::Reference< ucb::XContentIdentifier >& Identifier,
281 : bool bIsFolder )
282 : throw ( ucb::ContentCreationException )
283 : : ContentImplHelper( rxContext, pProvider, Identifier ),
284 : m_pProvider( pProvider ),
285 : m_pSession( NULL ),
286 0 : m_sURL( Identifier->getContentIdentifier( ) ),
287 0 : m_aURL( Identifier->getContentIdentifier( ) ),
288 : m_bTransient( true ),
289 0 : m_bIsFolder( bIsFolder )
290 : {
291 : SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL );
292 :
293 0 : m_sObjectPath = m_aURL.getObjectPath( );
294 0 : m_sObjectId = m_aURL.getObjectId( );
295 0 : }
296 :
297 0 : Content::~Content()
298 : {
299 0 : }
300 :
301 0 : libcmis::Session* Content::getSession( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
302 : {
303 : // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
304 0 : ucbhelper::InternetProxyDecider aProxyDecider( m_xContext );
305 0 : INetURLObject aBindingUrl( m_aURL.getBindingUrl( ) );
306 : const ucbhelper::InternetProxyServer& rProxy = aProxyDecider.getProxy(
307 0 : INetURLObject::GetScheme( aBindingUrl.GetProtocol( ) ), aBindingUrl.GetHost(), aBindingUrl.GetPort() );
308 0 : OUString sProxy = rProxy.aName;
309 0 : if ( rProxy.nPort > 0 )
310 0 : sProxy += ":" + OUString::number( rProxy.nPort );
311 0 : libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy ), string(), string(), string() );
312 :
313 : // Look for a cached session, key is binding url + repo id
314 0 : OUString sSessionId = m_aURL.getBindingUrl( ) + m_aURL.getRepositoryId( );
315 0 : if ( NULL == m_pSession )
316 0 : m_pSession = m_pProvider->getSession( sSessionId );
317 :
318 0 : if ( NULL == m_pSession )
319 : {
320 : #ifndef SYSTEM_CURL
321 : // Initialize NSS library to make sure libcmis (and curl) can access CACERTs using NSS
322 : // when using internal libcurl.
323 : uno::Reference< com::sun::star::xml::crypto::XNSSInitializer >
324 : xNSSInitializer = com::sun::star::xml::crypto::NSSInitializer::create( m_xContext );
325 :
326 : uno::Reference< com::sun::star::xml::crypto::XDigestContext > xDigestContext(
327 : xNSSInitializer->getDigestContext( com::sun::star::xml::crypto::DigestID::SHA256,
328 : uno::Sequence< beans::NamedValue >() ),
329 : uno::UNO_SET_THROW );
330 : #endif
331 :
332 : // Set the SSL Validation handler
333 : libcmis::CertValidationHandlerPtr certHandler(
334 0 : new CertValidationHandler( xEnv, m_xContext, aBindingUrl.GetHost( ) ) );
335 0 : libcmis::SessionFactory::setCertificateValidationHandler( certHandler );
336 :
337 : // Get the auth credentials
338 0 : AuthProvider authProvider( xEnv, m_xIdentifier->getContentIdentifier( ), m_aURL.getBindingUrl( ) );
339 0 : AuthProvider::setXEnv( xEnv );
340 :
341 0 : string rUsername = OUSTR_TO_STDSTR( m_aURL.getUsername( ) );
342 0 : string rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );
343 0 : if ( authProvider.authenticationQuery( rUsername, rPassword ) )
344 : {
345 : // Initiate a CMIS session and register it as we found nothing
346 0 : libcmis::OAuth2DataPtr oauth2Data;
347 0 : if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
348 : oauth2Data.reset( new libcmis::OAuth2Data(
349 : GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
350 : GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
351 0 : GDRIVE_CLIENT_ID, GDRIVE_CLIENT_SECRET ) );
352 0 : if ( m_aURL.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL ) )
353 : oauth2Data.reset( new libcmis::OAuth2Data(
354 : ALFRESCO_CLOUD_AUTH_URL, ALFRESCO_CLOUD_TOKEN_URL,
355 : ALFRESCO_CLOUD_SCOPE, ALFRESCO_CLOUD_REDIRECT_URI,
356 0 : ALFRESCO_CLOUD_CLIENT_ID, ALFRESCO_CLOUD_CLIENT_SECRET ) );
357 0 : if ( m_aURL.getBindingUrl( ) == ONEDRIVE_BASE_URL )
358 : {
359 0 : libcmis::SessionFactory::setOAuth2AuthCodeProvider( authProvider.onedriveAuthCodeFallback );
360 : oauth2Data.reset( new libcmis::OAuth2Data(
361 : ONEDRIVE_AUTH_URL, ONEDRIVE_TOKEN_URL,
362 : ONEDRIVE_SCOPE, ONEDRIVE_REDIRECT_URI,
363 0 : ONEDRIVE_CLIENT_ID, ONEDRIVE_CLIENT_SECRET ) );
364 : }
365 :
366 : m_pSession = libcmis::SessionFactory::createSession(
367 0 : OUSTR_TO_STDSTR( m_aURL.getBindingUrl( ) ),
368 0 : rUsername, rPassword, OUSTR_TO_STDSTR( m_aURL.getRepositoryId( ) ), false, oauth2Data );
369 0 : if ( m_pSession == NULL )
370 : ucbhelper::cancelCommandExecution(
371 : ucb::IOErrorCode_INVALID_DEVICE,
372 : uno::Sequence< uno::Any >( 0 ),
373 : xEnv,
374 0 : OUString( ) );
375 0 : m_pProvider->registerSession( sSessionId, m_pSession );
376 : }
377 : else
378 : {
379 : // Silently fail as the user cancelled the authentication
380 0 : throw uno::RuntimeException( );
381 0 : }
382 : }
383 0 : return m_pSession;
384 : }
385 :
386 0 : libcmis::ObjectTypePtr Content::getObjectType( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
387 : {
388 0 : if ( NULL == m_pObjectType.get( ) && m_bTransient )
389 : {
390 0 : string typeId = m_bIsFolder ? "cmis:folder" : "cmis:document";
391 : // The type to create needs to be fetched from the possible children types
392 : // defined in the parent folder. Then, we'll pick up the first one we find matching
393 : // cmis:folder or cmis:document (depending what we need to create).
394 : // The easy case will work in most cases, but not on some servers (like Lotus Live)
395 0 : libcmis::Folder* pParent = NULL;
396 0 : bool bTypeRestricted = false;
397 : try
398 : {
399 0 : pParent = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) );
400 : }
401 0 : catch ( const libcmis::Exception& )
402 : {
403 : }
404 :
405 0 : if ( pParent )
406 : {
407 0 : map< string, libcmis::PropertyPtr >& aProperties = pParent->getProperties( );
408 0 : map< string, libcmis::PropertyPtr >::iterator it = aProperties.find( "cmis:allowedChildObjectTypeIds" );
409 0 : if ( it != aProperties.end( ) )
410 : {
411 0 : libcmis::PropertyPtr pProperty = it->second;
412 0 : if ( pProperty )
413 : {
414 0 : vector< string > typesIds = pProperty->getStrings( );
415 0 : for ( vector< string >::iterator typeIt = typesIds.begin();
416 0 : typeIt != typesIds.end() && !m_pObjectType; ++typeIt )
417 : {
418 0 : bTypeRestricted = true;
419 0 : libcmis::ObjectTypePtr type = getSession( xEnv )->getType( *typeIt );
420 :
421 : // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
422 0 : if ( type->getBaseType( )->getId( ) == typeId )
423 0 : m_pObjectType = type;
424 0 : }
425 0 : }
426 : }
427 : }
428 :
429 0 : if ( !bTypeRestricted )
430 0 : m_pObjectType = getSession( xEnv )->getType( typeId );
431 : }
432 0 : return m_pObjectType;
433 : }
434 :
435 :
436 0 : libcmis::ObjectPtr Content::getObject( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw (css::uno::RuntimeException, css::ucb::CommandFailedException, libcmis::Exception)
437 : {
438 : // can't get the session for some reason
439 : // the recent file openning at start up is an example.
440 : try
441 : {
442 0 : if ( !getSession( xEnv ) )
443 0 : return m_pObject;
444 : }
445 0 : catch ( uno::RuntimeException& )
446 : {
447 0 : return m_pObject;
448 : }
449 0 : if ( !m_pObject.get() )
450 : {
451 0 : if ( !m_sObjectId.isEmpty( ) )
452 : {
453 : try
454 : {
455 0 : m_pObject = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) );
456 : }
457 0 : catch ( const libcmis::Exception& )
458 : {
459 0 : throw libcmis::Exception( "Object not found" );
460 : }
461 : }
462 0 : else if ( !m_sObjectPath.isEmpty( ) )
463 : {
464 : try
465 : {
466 0 : m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) );
467 : }
468 0 : catch ( const libcmis::Exception& )
469 : {
470 : // In some cases, getting the object from the path doesn't work,
471 : // but getting the parent from its path and the get the child in the list is OK.
472 : // It's weird, but needed to handle case where the path isn't the folders/files
473 : // names separated by '/' (as in Lotus Live)
474 0 : INetURLObject aParentUrl( m_sURL );
475 0 : string sName = OUSTR_TO_STDSTR( aParentUrl.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ) );
476 0 : aParentUrl.removeSegment( );
477 0 : OUString sParentUrl = aParentUrl.GetMainURL( INetURLObject::NO_DECODE );
478 :
479 0 : Content aParent( m_xContext, m_pProvider, new ucbhelper::ContentIdentifier( sParentUrl ) );
480 0 : libcmis::FolderPtr pParentFolder = boost::dynamic_pointer_cast< libcmis::Folder >( aParent.getObject( xEnv ) );
481 0 : if ( pParentFolder )
482 : {
483 0 : vector< libcmis::ObjectPtr > children = pParentFolder->getChildren( );
484 0 : for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
485 0 : it != children.end() && !m_pObject; ++it )
486 : {
487 0 : if ( ( *it )->getName( ) == sName )
488 0 : m_pObject = *it;
489 0 : }
490 : }
491 :
492 0 : if ( !m_pObject )
493 0 : throw libcmis::Exception( "Object not found" );
494 : }
495 : }
496 : else
497 : {
498 0 : m_pObject = getSession( xEnv )->getRootFolder( );
499 0 : m_sObjectPath = "/";
500 0 : m_sObjectId = OUString( );
501 : }
502 : }
503 :
504 0 : return m_pObject;
505 : }
506 :
507 0 : bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
508 : {
509 0 : bool bIsFolder = false;
510 : try
511 : {
512 0 : libcmis::ObjectPtr obj = getObject( xEnv );
513 0 : if ( obj )
514 0 : bIsFolder = obj->getBaseType( ) == "cmis:folder";
515 : }
516 0 : catch ( const libcmis::Exception& e )
517 : {
518 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
519 : ucbhelper::cancelCommandExecution(
520 : ucb::IOErrorCode_GENERAL,
521 : uno::Sequence< uno::Any >( 0 ),
522 : xEnv,
523 0 : OUString::createFromAscii( e.what( ) ) );
524 : }
525 0 : return bIsFolder;
526 : }
527 :
528 0 : uno::Any Content::getBadArgExcept()
529 : {
530 : return uno::makeAny( lang::IllegalArgumentException(
531 : OUString("Wrong argument type!"),
532 0 : static_cast< cppu::OWeakObject * >( this ), -1) );
533 : }
534 :
535 0 : libcmis::ObjectPtr Content::updateProperties(
536 : const uno::Any& iCmisProps,
537 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
538 : {
539 : // Convert iCmisProps to Cmis Properties;
540 0 : uno::Sequence< document::CmisProperty > aPropsSeq;
541 0 : iCmisProps >>= aPropsSeq;
542 0 : map< string, libcmis::PropertyPtr > aProperties;
543 :
544 0 : sal_Int32 propsLen = aPropsSeq.getLength( );
545 0 : for ( sal_Int32 i = 0; i< propsLen; i++ )
546 : {
547 0 : std::string id = OUSTR_TO_STDSTR( aPropsSeq[i].Id );
548 0 : libcmis::PropertyPtr prop = lcl_unoToCmisProperty( aPropsSeq[i] );
549 0 : aProperties.insert( std::pair<string, libcmis::PropertyPtr>( id, prop ) );
550 0 : }
551 0 : libcmis::ObjectPtr updateObj;
552 : try
553 : {
554 0 : updateObj = getObject( xEnv )->updateProperties( aProperties );
555 : }
556 0 : catch ( const libcmis::Exception& e )
557 : {
558 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e.what( ) );
559 : }
560 :
561 0 : return updateObj;
562 : }
563 :
564 0 : uno::Reference< sdbc::XRow > Content::getPropertyValues(
565 : const uno::Sequence< beans::Property >& rProperties,
566 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
567 : {
568 0 : rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
569 :
570 : sal_Int32 nProps;
571 : const beans::Property* pProps;
572 :
573 0 : nProps = rProperties.getLength();
574 0 : pProps = rProperties.getConstArray();
575 :
576 0 : for( sal_Int32 n = 0; n < nProps; ++n )
577 : {
578 0 : const beans::Property& rProp = pProps[ n ];
579 :
580 : try
581 : {
582 0 : if ( rProp.Name == "IsDocument" )
583 : {
584 : try
585 : {
586 0 : libcmis::ObjectPtr obj = getObject( xEnv );
587 0 : if ( obj )
588 0 : xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:document" );
589 : }
590 0 : catch ( const libcmis::Exception& )
591 : {
592 0 : if ( m_pObjectType.get( ) )
593 0 : xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:document" );
594 : else
595 0 : xRow->appendVoid( rProp );
596 : }
597 : }
598 0 : else if ( rProp.Name == "IsFolder" )
599 : {
600 : try
601 : {
602 0 : libcmis::ObjectPtr obj = getObject( xEnv );
603 0 : if ( obj )
604 0 : xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:folder" );
605 : else
606 0 : xRow->appendBoolean( rProp, false );
607 : }
608 0 : catch ( const libcmis::Exception& )
609 : {
610 0 : if ( m_pObjectType.get( ) )
611 0 : xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:folder" );
612 : else
613 0 : xRow->appendVoid( rProp );
614 : }
615 : }
616 0 : else if ( rProp.Name == "Title" )
617 : {
618 0 : OUString sTitle;
619 : try
620 : {
621 0 : sTitle = STD_TO_OUSTR( getObject( xEnv )->getName() );
622 : }
623 0 : catch ( const libcmis::Exception& )
624 : {
625 0 : if ( !m_pObjectProps.empty() )
626 : {
627 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
628 0 : if ( it != m_pObjectProps.end( ) )
629 : {
630 0 : vector< string > values = it->second->getStrings( );
631 0 : if ( !values.empty() )
632 0 : sTitle = STD_TO_OUSTR( values.front( ) );
633 : }
634 : }
635 : }
636 :
637 : // Nothing worked... get it from the path
638 0 : if ( sTitle.isEmpty( ) )
639 : {
640 0 : OUString sPath = m_sObjectPath;
641 :
642 : // Get rid of the trailing slash problem
643 0 : if ( sPath.endsWith("/") )
644 0 : sPath = sPath.copy( 0, sPath.getLength() - 1 );
645 :
646 : // Get the last segment
647 0 : sal_Int32 nPos = sPath.lastIndexOf( '/' );
648 0 : if ( nPos >= 0 )
649 0 : sTitle = sPath.copy( nPos + 1 );
650 : }
651 :
652 0 : if ( !sTitle.isEmpty( ) )
653 0 : xRow->appendString( rProp, sTitle );
654 : else
655 0 : xRow->appendVoid( rProp );
656 : }
657 0 : else if ( rProp.Name == "ObjectId" )
658 : {
659 0 : OUString sId;
660 : try
661 : {
662 0 : sId = STD_TO_OUSTR( getObject( xEnv )->getId() );
663 : }
664 0 : catch ( const libcmis::Exception& )
665 : {
666 0 : if ( !m_pObjectProps.empty() )
667 : {
668 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:objectId" );
669 0 : if ( it != m_pObjectProps.end( ) )
670 : {
671 0 : vector< string > values = it->second->getStrings( );
672 0 : if ( !values.empty() )
673 0 : sId = STD_TO_OUSTR( values.front( ) );
674 : }
675 : }
676 : }
677 :
678 0 : if ( !sId.isEmpty( ) )
679 0 : xRow->appendString( rProp, sId );
680 : else
681 0 : xRow->appendVoid( rProp );
682 : }
683 0 : else if ( rProp.Name == "TitleOnServer" )
684 : {
685 0 : xRow->appendString( rProp, m_sObjectPath);
686 : }
687 0 : else if ( rProp.Name == "IsReadOnly" )
688 : {
689 0 : boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject( xEnv )->getAllowableActions( );
690 0 : bool bReadOnly = false;
691 0 : if ( !allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) &&
692 0 : !allowableActions->isAllowed( libcmis::ObjectAction::CheckIn ) )
693 0 : bReadOnly = true;
694 :
695 0 : xRow->appendBoolean( rProp, bReadOnly );
696 : }
697 0 : else if ( rProp.Name == "DateCreated" )
698 : {
699 0 : util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getCreationDate( ) );
700 0 : xRow->appendTimestamp( rProp, aTime );
701 : }
702 0 : else if ( rProp.Name == "DateModified" )
703 : {
704 0 : util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getLastModificationDate( ) );
705 0 : xRow->appendTimestamp( rProp, aTime );
706 : }
707 0 : else if ( rProp.Name == "Size" )
708 : {
709 : try
710 : {
711 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
712 0 : if ( NULL != document )
713 0 : xRow->appendLong( rProp, document->getContentLength() );
714 : else
715 0 : xRow->appendVoid( rProp );
716 : }
717 0 : catch ( const libcmis::Exception& )
718 : {
719 0 : xRow->appendVoid( rProp );
720 : }
721 : }
722 0 : else if ( rProp.Name == "CreatableContentsInfo" )
723 : {
724 0 : xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
725 : }
726 0 : else if ( rProp.Name == "MediaType" )
727 : {
728 : try
729 : {
730 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
731 0 : if ( NULL != document )
732 0 : xRow->appendString( rProp, STD_TO_OUSTR( document->getContentType() ) );
733 : else
734 0 : xRow->appendVoid( rProp );
735 : }
736 0 : catch ( const libcmis::Exception& )
737 : {
738 0 : xRow->appendVoid( rProp );
739 : }
740 : }
741 0 : else if ( rProp.Name == "IsVolume" )
742 : {
743 0 : xRow->appendBoolean( rProp, false );
744 : }
745 0 : else if ( rProp.Name == "IsRemote" )
746 : {
747 0 : xRow->appendBoolean( rProp, false );
748 : }
749 0 : else if ( rProp.Name == "IsRemoveable" )
750 : {
751 0 : xRow->appendBoolean( rProp, false );
752 : }
753 0 : else if ( rProp.Name == "IsFloppy" )
754 : {
755 0 : xRow->appendBoolean( rProp, false );
756 : }
757 0 : else if ( rProp.Name == "IsCompactDisc" )
758 : {
759 0 : xRow->appendBoolean( rProp, false );
760 : }
761 0 : else if ( rProp.Name == "IsHidden" )
762 : {
763 0 : xRow->appendBoolean( rProp, false );
764 : }
765 0 : else if ( rProp.Name == "TargetURL" )
766 : {
767 0 : xRow->appendString( rProp, "" );
768 : }
769 0 : else if ( rProp.Name == "BaseURI" )
770 : {
771 0 : xRow->appendString( rProp, m_aURL.getBindingUrl( ) );
772 : }
773 0 : else if ( rProp.Name == "CmisProperties" )
774 : {
775 : try
776 : {
777 0 : libcmis::ObjectPtr object = getObject( xEnv );
778 0 : map< string, libcmis::PropertyPtr >& aProperties = object->getProperties( );
779 0 : uno::Sequence< document::CmisProperty > aCmisProperties( aProperties.size( ) );
780 0 : document::CmisProperty* pCmisProps = aCmisProperties.getArray( );
781 0 : sal_Int32 i = 0;
782 0 : for ( map< string, libcmis::PropertyPtr >::iterator it = aProperties.begin();
783 0 : it != aProperties.end( ); ++it, ++i )
784 : {
785 0 : string sId = it->first;
786 0 : string sDisplayName = it->second->getPropertyType()->getDisplayName( );
787 0 : bool bUpdatable = it->second->getPropertyType()->isUpdatable( );
788 0 : bool bRequired = it->second->getPropertyType()->isRequired( );
789 0 : bool bMultiValued = it->second->getPropertyType()->isMultiValued();
790 0 : bool bOpenChoice = it->second->getPropertyType()->isOpenChoice();
791 :
792 0 : pCmisProps[i].Id = STD_TO_OUSTR( sId );
793 0 : pCmisProps[i].Name = STD_TO_OUSTR( sDisplayName );
794 0 : pCmisProps[i].Updatable = bUpdatable;
795 0 : pCmisProps[i].Required = bRequired;
796 0 : pCmisProps[i].MultiValued = bMultiValued;
797 0 : pCmisProps[i].OpenChoice = bOpenChoice;
798 0 : pCmisProps[i].Value = lcl_cmisPropertyToUno( it->second );
799 0 : switch ( it->second->getPropertyType( )->getType( ) )
800 : {
801 : default:
802 : case libcmis::PropertyType::String:
803 0 : pCmisProps[i].Type = CMIS_TYPE_STRING;
804 0 : break;
805 : case libcmis::PropertyType::Integer:
806 0 : pCmisProps[i].Type = CMIS_TYPE_INTEGER;
807 0 : break;
808 : case libcmis::PropertyType::Decimal:
809 0 : pCmisProps[i].Type = CMIS_TYPE_DECIMAL;
810 0 : break;
811 : case libcmis::PropertyType::Bool:
812 0 : pCmisProps[i].Type = CMIS_TYPE_BOOL;
813 0 : break;
814 : case libcmis::PropertyType::DateTime:
815 0 : pCmisProps[i].Type = CMIS_TYPE_DATETIME;
816 0 : break;
817 : }
818 :
819 0 : }
820 0 : xRow->appendObject( rProp.Name, uno::makeAny( aCmisProperties ) );
821 : }
822 0 : catch ( const libcmis::Exception& )
823 : {
824 0 : xRow->appendVoid( rProp );
825 : }
826 : }
827 0 : else if ( rProp.Name == "IsVersionable" )
828 : {
829 : try
830 : {
831 0 : libcmis::ObjectPtr object = getObject( xEnv );
832 0 : bool bIsVersionable = object->getTypeDescription( )->isVersionable( );
833 0 : xRow->appendBoolean( rProp, bIsVersionable );
834 : }
835 0 : catch ( const libcmis::Exception& )
836 : {
837 0 : xRow->appendVoid( rProp );
838 : }
839 : }
840 0 : else if ( rProp.Name == "CanCheckOut" )
841 : {
842 : try
843 : {
844 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
845 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
846 0 : bool bAllowed = false;
847 0 : if ( aAllowables )
848 : {
849 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckOut );
850 : }
851 0 : xRow->appendBoolean( rProp, bAllowed );
852 : }
853 0 : catch ( const libcmis::Exception& )
854 : {
855 0 : xRow->appendVoid( rProp );
856 : }
857 : }
858 0 : else if ( rProp.Name == "CanCancelCheckOut" )
859 : {
860 : try
861 : {
862 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
863 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
864 0 : bool bAllowed = false;
865 0 : if ( aAllowables )
866 : {
867 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CancelCheckOut );
868 : }
869 0 : xRow->appendBoolean( rProp, bAllowed );
870 : }
871 0 : catch ( const libcmis::Exception& )
872 : {
873 0 : xRow->appendVoid( rProp );
874 : }
875 : }
876 0 : else if ( rProp.Name == "CanCheckIn" )
877 : {
878 : try
879 : {
880 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
881 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
882 0 : bool bAllowed = false;
883 0 : if ( aAllowables )
884 : {
885 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckIn );
886 : }
887 0 : xRow->appendBoolean( rProp, bAllowed );
888 : }
889 0 : catch ( const libcmis::Exception& )
890 : {
891 0 : xRow->appendVoid( rProp );
892 : }
893 : }
894 : else
895 : SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp.Name );
896 : }
897 0 : catch (const libcmis::Exception&)
898 : {
899 0 : xRow->appendVoid( rProp );
900 : }
901 : }
902 :
903 0 : return uno::Reference< sdbc::XRow >( xRow.get() );
904 : }
905 :
906 0 : uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand,
907 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
908 : throw( uno::Exception, libcmis::Exception )
909 : {
910 0 : bool bIsFolder = isFolder( xEnv );
911 :
912 : // Handle the case of the non-existing file
913 0 : if ( !getObject( xEnv ) )
914 : {
915 0 : uno::Sequence< uno::Any > aArgs( 1 );
916 0 : aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
917 : uno::Any aErr = uno::makeAny(
918 : ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject * >( this ),
919 : task::InteractionClassification_ERROR,
920 : bIsFolder ? ucb::IOErrorCode_NOT_EXISTING_PATH : ucb::IOErrorCode_NOT_EXISTING, aArgs)
921 0 : );
922 :
923 0 : ucbhelper::cancelCommandExecution(aErr, xEnv);
924 : }
925 :
926 0 : uno::Any aRet;
927 :
928 : bool bOpenFolder = (
929 0 : ( rOpenCommand.Mode == ucb::OpenMode::ALL ) ||
930 0 : ( rOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
931 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENTS )
932 0 : );
933 :
934 0 : if ( bOpenFolder && bIsFolder )
935 : {
936 : uno::Reference< ucb::XDynamicResultSet > xSet
937 0 : = new DynamicResultSet(m_xContext, this, rOpenCommand, xEnv );
938 0 : aRet <<= xSet;
939 : }
940 0 : else if ( rOpenCommand.Sink.is() )
941 : {
942 0 : if (
943 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
944 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
945 : )
946 : {
947 : ucbhelper::cancelCommandExecution(
948 : uno::makeAny ( ucb::UnsupportedOpenModeException
949 : ( OUString(), static_cast< cppu::OWeakObject * >( this ),
950 : sal_Int16( rOpenCommand.Mode ) ) ),
951 0 : xEnv );
952 : }
953 :
954 0 : if ( !feedSink( rOpenCommand.Sink, xEnv ) )
955 : {
956 : // Note: rOpenCommand.Sink may contain an XStream
957 : // implementation. Support for this type of
958 : // sink is optional...
959 : SAL_INFO( "ucb.ucp.cmis", "Failed to copy data to sink" );
960 :
961 : ucbhelper::cancelCommandExecution(
962 : uno::makeAny (ucb::UnsupportedDataSinkException
963 : ( OUString(), static_cast< cppu::OWeakObject * >( this ),
964 : rOpenCommand.Sink ) ),
965 0 : xEnv );
966 : }
967 : }
968 : else
969 : SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
970 :
971 0 : return aRet;
972 : }
973 :
974 0 : OUString Content::checkIn( const ucb::CheckinArgument& rArg,
975 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
976 : throw( uno::Exception )
977 : {
978 0 : ucbhelper::Content aSourceContent( rArg.SourceURL, xEnv, comphelper::getProcessComponentContext( ) );
979 0 : uno::Reference< io::XInputStream > xIn = aSourceContent.openStream( );
980 :
981 0 : libcmis::ObjectPtr object;
982 : try
983 : {
984 0 : object = getObject( xEnv );
985 : }
986 0 : catch ( const libcmis::Exception& )
987 : {
988 : }
989 :
990 0 : libcmis::Document* pPwc = dynamic_cast< libcmis::Document* >( object.get( ) );
991 0 : if ( !pPwc )
992 : {
993 : ucbhelper::cancelCommandExecution(
994 : ucb::IOErrorCode_GENERAL,
995 : uno::Sequence< uno::Any >( 0 ),
996 : xEnv,
997 0 : "Checkin only supported by documents" );
998 : }
999 :
1000 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1001 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1002 0 : copyData( xIn, xOutput );
1003 :
1004 0 : map< string, libcmis::PropertyPtr > newProperties;
1005 : libcmis::DocumentPtr pDoc = pPwc->checkIn( rArg.MajorVersion, OUSTR_TO_STDSTR( rArg.VersionComment ), newProperties,
1006 0 : pOut, OUSTR_TO_STDSTR( rArg.MimeType ), OUSTR_TO_STDSTR( rArg.NewTitle ) );
1007 :
1008 : // Get the URL and send it back as a result
1009 0 : URL aCmisUrl( m_sURL );
1010 0 : vector< string > aPaths = pDoc->getPaths( );
1011 0 : if ( !aPaths.empty() )
1012 : {
1013 0 : string sPath = aPaths.front( );
1014 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
1015 : }
1016 : else
1017 : {
1018 : // We may have unfiled document depending on the server, those
1019 : // won't have any path, use their ID instead
1020 0 : string sId = pDoc->getId( );
1021 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
1022 : }
1023 0 : return aCmisUrl.asString( );
1024 : }
1025 :
1026 0 : OUString Content::checkOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1027 : throw( uno::Exception )
1028 : {
1029 0 : OUString aRet;
1030 : try
1031 : {
1032 : // Checkout the document if possible
1033 0 : libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
1034 0 : if ( pDoc.get( ) == NULL )
1035 : {
1036 : ucbhelper::cancelCommandExecution(
1037 : ucb::IOErrorCode_GENERAL,
1038 : uno::Sequence< uno::Any >( 0 ),
1039 : xEnv,
1040 0 : "Checkout only supported by documents" );
1041 : }
1042 0 : libcmis::DocumentPtr pPwc = pDoc->checkOut( );
1043 :
1044 : // Compute the URL of the Private Working Copy (PWC)
1045 0 : URL aCmisUrl( m_sURL );
1046 0 : vector< string > aPaths = pPwc->getPaths( );
1047 0 : if ( !aPaths.empty() )
1048 : {
1049 0 : string sPath = aPaths.front( );
1050 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
1051 : }
1052 : else
1053 : {
1054 : // We may have unfiled PWC depending on the server, those
1055 : // won't have any path, use their ID instead
1056 0 : string sId = pPwc->getId( );
1057 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
1058 : }
1059 0 : aRet = aCmisUrl.asString( );
1060 : }
1061 0 : catch ( const libcmis::Exception& e )
1062 : {
1063 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1064 : ucbhelper::cancelCommandExecution(
1065 : ucb::IOErrorCode_GENERAL,
1066 : uno::Sequence< uno::Any >( 0 ),
1067 : xEnv,
1068 0 : OUString::createFromAscii( e.what() ) );
1069 : }
1070 0 : return aRet;
1071 : }
1072 :
1073 0 : OUString Content::cancelCheckOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1074 : throw( uno::Exception )
1075 : {
1076 0 : OUString aRet;
1077 : try
1078 : {
1079 0 : libcmis::DocumentPtr pPwc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
1080 0 : if ( pPwc.get( ) == NULL )
1081 : {
1082 : ucbhelper::cancelCommandExecution(
1083 : ucb::IOErrorCode_GENERAL,
1084 : uno::Sequence< uno::Any >( 0 ),
1085 : xEnv,
1086 0 : "CancelCheckout only supported by documents" );
1087 : }
1088 0 : pPwc->cancelCheckout( );
1089 :
1090 : // Get the Original document (latest version)
1091 0 : vector< libcmis::DocumentPtr > aVersions = pPwc->getAllVersions( );
1092 0 : bool bFound = false;
1093 0 : for ( vector< libcmis::DocumentPtr >::iterator it = aVersions.begin();
1094 0 : it != aVersions.end( ) && !bFound; ++it )
1095 : {
1096 0 : libcmis::DocumentPtr pVersion = *it;
1097 0 : map< string, libcmis::PropertyPtr > aProps = pVersion->getProperties( );
1098 0 : bool bIsLatestVersion = false;
1099 0 : map< string, libcmis::PropertyPtr >::iterator propIt = aProps.find( string( "cmis:isLatestVersion" ) );
1100 0 : if ( propIt != aProps.end( ) && !propIt->second->getBools( ).empty( ) )
1101 : {
1102 0 : bIsLatestVersion = propIt->second->getBools( ).front( );
1103 : }
1104 :
1105 0 : if ( bIsLatestVersion )
1106 : {
1107 0 : bFound = true;
1108 : // Compute the URL of the Document
1109 0 : URL aCmisUrl( m_sURL );
1110 0 : vector< string > aPaths = pVersion->getPaths( );
1111 0 : if ( !aPaths.empty() )
1112 : {
1113 0 : string sPath = aPaths.front( );
1114 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
1115 : }
1116 : else
1117 : {
1118 : // We may have unfiled doc depending on the server, those
1119 : // won't have any path, use their ID instead
1120 0 : string sId = pVersion->getId( );
1121 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
1122 : }
1123 0 : aRet = aCmisUrl.asString( );
1124 : }
1125 0 : }
1126 : }
1127 0 : catch ( const libcmis::Exception& e )
1128 : {
1129 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1130 : ucbhelper::cancelCommandExecution(
1131 : ucb::IOErrorCode_GENERAL,
1132 : uno::Sequence< uno::Any >( 0 ),
1133 : xEnv,
1134 0 : OUString::createFromAscii( e.what() ) );
1135 : }
1136 0 : return aRet;
1137 : }
1138 :
1139 0 : uno::Sequence< document::CmisVersion> Content::getAllVersions( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1140 : throw( uno::Exception, std::exception )
1141 : {
1142 : try
1143 : {
1144 : // get the document
1145 0 : libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
1146 0 : if ( pDoc.get( ) == NULL )
1147 : {
1148 : ucbhelper::cancelCommandExecution(
1149 : ucb::IOErrorCode_GENERAL,
1150 : uno::Sequence< uno::Any >( 0 ),
1151 : xEnv,
1152 0 : "Can not get the document" );
1153 : }
1154 0 : vector< libcmis::DocumentPtr > aCmisVersions = pDoc->getAllVersions( );
1155 0 : uno::Sequence< document::CmisVersion > aVersions( aCmisVersions.size( ) );
1156 0 : int i = 0;
1157 0 : for ( vector< libcmis::DocumentPtr >::iterator it = aCmisVersions.begin();
1158 0 : it != aCmisVersions.end( ); ++it, ++i )
1159 : {
1160 0 : libcmis::DocumentPtr pVersion = *it;
1161 0 : aVersions[i].Id = STD_TO_OUSTR( pVersion->getId( ) );
1162 0 : aVersions[i].Author = STD_TO_OUSTR( pVersion->getCreatedBy( ) );
1163 0 : aVersions[i].TimeStamp = lcl_boostToUnoTime( pVersion->getLastModificationDate( ) );
1164 0 : aVersions[i].Comment = STD_TO_OUSTR( pVersion->getStringProperty("cmis:checkinComment") );
1165 0 : }
1166 0 : return aVersions;
1167 : }
1168 0 : catch ( const libcmis::Exception& e )
1169 : {
1170 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1171 : ucbhelper::cancelCommandExecution(
1172 : ucb::IOErrorCode_GENERAL,
1173 : uno::Sequence< uno::Any >( 0 ),
1174 : xEnv,
1175 0 : OUString::createFromAscii( e.what() ) );
1176 : }
1177 0 : return uno::Sequence< document::CmisVersion > ( );
1178 : }
1179 :
1180 0 : void Content::transfer( const ucb::TransferInfo& rTransferInfo,
1181 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1182 : throw( uno::Exception )
1183 : {
1184 : // If the source isn't on the same CMIS repository, then simply copy
1185 0 : INetURLObject aSourceUrl( rTransferInfo.SourceURL );
1186 0 : if ( aSourceUrl.GetProtocol() != INetProtocol::Cmis )
1187 : {
1188 0 : OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( );
1189 0 : if ( sSrcBindingUrl != m_aURL.getBindingUrl( ) )
1190 : {
1191 : ucbhelper::cancelCommandExecution(
1192 : uno::makeAny(
1193 : ucb::InteractiveBadTransferURLException(
1194 : OUString("Unsupported URL scheme!"),
1195 : static_cast< cppu::OWeakObject * >( this ) ) ),
1196 0 : xEnv );
1197 0 : }
1198 : }
1199 :
1200 0 : SAL_INFO( "ucb.ucp.cmis", "TODO - Content::transfer()" );
1201 0 : }
1202 :
1203 0 : void Content::insert( const uno::Reference< io::XInputStream > & xInputStream,
1204 : bool bReplaceExisting, const OUString& rMimeType,
1205 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1206 : throw (uno::Exception, std::exception)
1207 : {
1208 0 : if ( !xInputStream.is() )
1209 : {
1210 : ucbhelper::cancelCommandExecution( uno::makeAny
1211 : ( ucb::MissingInputStreamException
1212 : ( OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
1213 0 : xEnv );
1214 : }
1215 :
1216 : // For transient content, the URL is the one of the parent
1217 0 : if ( m_bTransient )
1218 : {
1219 0 : OUString sNewPath;
1220 :
1221 : // Try to get the object from the server if there is any
1222 0 : libcmis::FolderPtr pFolder;
1223 : try
1224 : {
1225 0 : pFolder = boost::dynamic_pointer_cast< libcmis::Folder >( getObject( xEnv ) );
1226 : }
1227 0 : catch ( const libcmis::Exception& )
1228 : {
1229 : }
1230 :
1231 0 : if ( pFolder != 0 )
1232 : {
1233 0 : libcmis::ObjectPtr object;
1234 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
1235 0 : if ( it == m_pObjectProps.end( ) )
1236 : {
1237 : ucbhelper::cancelCommandExecution( uno::makeAny
1238 : ( uno::RuntimeException( "Missing name property",
1239 : static_cast< cppu::OWeakObject * >( this ) ) ),
1240 0 : xEnv );
1241 : }
1242 0 : string newName = it->second->getStrings( ).front( );
1243 0 : string newPath = OUSTR_TO_STDSTR( m_sObjectPath );
1244 0 : if ( !newPath.empty( ) && newPath[ newPath.size( ) - 1 ] != '/' )
1245 0 : newPath += "/";
1246 0 : newPath += newName;
1247 : try
1248 : {
1249 0 : if ( !m_sObjectId.isEmpty( ) )
1250 0 : object = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId) );
1251 : else
1252 0 : object = getSession( xEnv )->getObjectByPath( newPath );
1253 0 : sNewPath = STD_TO_OUSTR( newPath );
1254 : }
1255 0 : catch ( const libcmis::Exception& )
1256 : {
1257 : // Nothing matched the path
1258 : }
1259 :
1260 0 : if ( NULL != object.get( ) )
1261 : {
1262 : // Are the base type matching?
1263 0 : if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() )
1264 : {
1265 : ucbhelper::cancelCommandExecution( uno::makeAny
1266 : ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1267 : static_cast< cppu::OWeakObject * >( this ) ) ),
1268 0 : xEnv );
1269 : }
1270 :
1271 : // Update the existing object if it's a document
1272 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) );
1273 0 : if ( NULL != document )
1274 : {
1275 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1276 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1277 0 : copyData( xInputStream, xOutput );
1278 : try
1279 : {
1280 0 : document->setContentStream( pOut, OUSTR_TO_STDSTR( rMimeType ), string( ), bReplaceExisting );
1281 : }
1282 0 : catch ( const libcmis::Exception& )
1283 : {
1284 : ucbhelper::cancelCommandExecution( uno::makeAny
1285 : ( uno::RuntimeException( "Error when setting document content",
1286 : static_cast< cppu::OWeakObject * >( this ) ) ),
1287 0 : xEnv );
1288 0 : }
1289 : }
1290 : }
1291 : else
1292 : {
1293 : // We need to create a brand new object... either folder or document
1294 0 : bool bIsFolder = getObjectType( xEnv )->getBaseType( )->getId( ) == "cmis:folder";
1295 0 : setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv )->getId( ), xEnv );
1296 :
1297 0 : if ( bIsFolder )
1298 : {
1299 : try
1300 : {
1301 0 : libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps );
1302 0 : sNewPath = STD_TO_OUSTR( newPath );
1303 : }
1304 0 : catch ( const libcmis::Exception& )
1305 : {
1306 : ucbhelper::cancelCommandExecution( uno::makeAny
1307 : ( uno::RuntimeException( "Error when creating folder",
1308 : static_cast< cppu::OWeakObject * >( this ) ) ),
1309 0 : xEnv );
1310 : }
1311 : }
1312 : else
1313 : {
1314 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1315 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1316 0 : copyData( xInputStream, xOutput );
1317 : try
1318 : {
1319 0 : pFolder->createDocument( m_pObjectProps, pOut, OUSTR_TO_STDSTR( rMimeType ), string() );
1320 0 : sNewPath = STD_TO_OUSTR( newPath );
1321 : }
1322 0 : catch ( const libcmis::Exception& )
1323 : {
1324 : ucbhelper::cancelCommandExecution( uno::makeAny
1325 : ( uno::RuntimeException( "Error when creating document",
1326 : static_cast< cppu::OWeakObject * >( this ) ) ),
1327 0 : xEnv );
1328 0 : }
1329 : }
1330 : }
1331 :
1332 0 : if ( !sNewPath.isEmpty( ) || !m_sObjectId.isEmpty( ) )
1333 : {
1334 : // Update the current content: it's no longer transient
1335 0 : m_sObjectPath = sNewPath;
1336 0 : URL aUrl( m_sURL );
1337 0 : aUrl.setObjectPath( m_sObjectPath );
1338 0 : aUrl.setObjectId( m_sObjectId );
1339 0 : m_sURL = aUrl.asString( );
1340 0 : m_pObject.reset( );
1341 0 : m_pObjectType.reset( );
1342 0 : m_pObjectProps.clear( );
1343 0 : m_bTransient = false;
1344 0 : inserted();
1345 0 : }
1346 0 : }
1347 : }
1348 0 : }
1349 :
1350 : const int TRANSFER_BUFFER_SIZE = 65536;
1351 :
1352 0 : void Content::copyData(
1353 : uno::Reference< io::XInputStream > xIn,
1354 : uno::Reference< io::XOutputStream > xOut )
1355 : {
1356 0 : uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
1357 :
1358 0 : while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
1359 0 : xOut->writeBytes( theData );
1360 :
1361 0 : xOut->closeOutput();
1362 0 : }
1363 :
1364 0 : uno::Sequence< uno::Any > Content::setPropertyValues(
1365 : const uno::Sequence< beans::PropertyValue >& rValues,
1366 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1367 : {
1368 : try
1369 : {
1370 : // Get the already set properties if possible
1371 0 : if ( !m_bTransient && getObject( xEnv ).get( ) )
1372 : {
1373 0 : m_pObjectProps.clear( );
1374 0 : m_pObjectType = getObject( xEnv )->getTypeDescription();
1375 : }
1376 : }
1377 0 : catch ( const libcmis::Exception& e )
1378 : {
1379 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1380 : ucbhelper::cancelCommandExecution(
1381 : ucb::IOErrorCode_GENERAL,
1382 : uno::Sequence< uno::Any >( 0 ),
1383 : xEnv,
1384 0 : OUString::createFromAscii( e.what() ) );
1385 : }
1386 :
1387 0 : sal_Int32 nCount = rValues.getLength();
1388 0 : uno::Sequence< uno::Any > aRet( nCount );
1389 :
1390 0 : bool bChanged = false;
1391 0 : const beans::PropertyValue* pValues = rValues.getConstArray();
1392 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
1393 : {
1394 0 : const beans::PropertyValue& rValue = pValues[ n ];
1395 0 : if ( rValue.Name == "ContentType" ||
1396 0 : rValue.Name == "MediaType" ||
1397 0 : rValue.Name == "IsDocument" ||
1398 0 : rValue.Name == "IsFolder" ||
1399 0 : rValue.Name == "Size" ||
1400 0 : rValue.Name == "CreatableContentsInfo" )
1401 : {
1402 : lang::IllegalAccessException e ( OUString("Property is read-only!"),
1403 0 : static_cast< cppu::OWeakObject* >( this ) );
1404 0 : aRet[ n ] <<= e;
1405 : }
1406 0 : else if ( rValue.Name == "Title" )
1407 : {
1408 0 : OUString aNewTitle;
1409 0 : if (!( rValue.Value >>= aNewTitle ))
1410 : {
1411 0 : aRet[ n ] <<= beans::IllegalTypeException
1412 : ( OUString("Property value has wrong type!"),
1413 0 : static_cast< cppu::OWeakObject * >( this ) );
1414 0 : continue;
1415 : }
1416 :
1417 0 : if ( aNewTitle.getLength() <= 0 )
1418 : {
1419 0 : aRet[ n ] <<= lang::IllegalArgumentException
1420 : ( OUString("Empty title not allowed!"),
1421 0 : static_cast< cppu::OWeakObject * >( this ), -1 );
1422 0 : continue;
1423 :
1424 : }
1425 :
1426 0 : setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ), xEnv );
1427 0 : bChanged = true;
1428 : }
1429 : else
1430 : {
1431 : SAL_INFO( "ucb.ucp.cmis", "Couln't set property: " << rValue.Name );
1432 : lang::IllegalAccessException e ( OUString("Property is read-only!"),
1433 0 : static_cast< cppu::OWeakObject* >( this ) );
1434 0 : aRet[ n ] <<= e;
1435 : }
1436 : }
1437 :
1438 : try
1439 : {
1440 0 : if ( !m_bTransient && bChanged )
1441 : {
1442 0 : getObject( xEnv )->updateProperties( m_pObjectProps );
1443 : }
1444 : }
1445 0 : catch ( const libcmis::Exception& e )
1446 : {
1447 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1448 : ucbhelper::cancelCommandExecution(
1449 : ucb::IOErrorCode_GENERAL,
1450 : uno::Sequence< uno::Any >( 0 ),
1451 : xEnv,
1452 0 : OUString::createFromAscii( e.what() ) );
1453 : }
1454 :
1455 0 : return aRet;
1456 : }
1457 :
1458 0 : bool Content::feedSink( uno::Reference< uno::XInterface> xSink,
1459 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1460 : {
1461 0 : if ( !xSink.is() )
1462 0 : return false;
1463 :
1464 0 : uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY );
1465 0 : uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY );
1466 0 : uno::Reference< io::XActiveDataStreamer > xDataStreamer = uno::Reference< io::XActiveDataStreamer >( xSink, uno::UNO_QUERY );
1467 :
1468 0 : if ( !xOut.is() && !xDataSink.is() && ( !xDataStreamer.is() || !xDataStreamer->getStream().is() ) )
1469 0 : return false;
1470 :
1471 0 : if ( xDataStreamer.is() && !xOut.is() )
1472 0 : xOut = xDataStreamer->getStream()->getOutputStream();
1473 :
1474 : try
1475 : {
1476 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get() );
1477 :
1478 0 : if (!document)
1479 0 : return false;
1480 :
1481 0 : boost::shared_ptr< istream > aIn = document->getContentStream( );
1482 :
1483 0 : uno::Reference< io::XInputStream > xIn = new ucbhelper::StdInputStream( aIn );
1484 0 : if( !xIn.is( ) )
1485 0 : return false;
1486 :
1487 0 : if ( xDataSink.is() )
1488 0 : xDataSink->setInputStream( xIn );
1489 0 : else if ( xOut.is() )
1490 0 : copyData( xIn, xOut );
1491 : }
1492 0 : catch ( const libcmis::Exception& e )
1493 : {
1494 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1495 : ucbhelper::cancelCommandExecution(
1496 : ucb::IOErrorCode_GENERAL,
1497 : uno::Sequence< uno::Any >( 0 ),
1498 : xEnv,
1499 0 : OUString::createFromAscii( e.what() ) );
1500 : }
1501 :
1502 0 : return true;
1503 : }
1504 :
1505 0 : uno::Sequence< beans::Property > Content::getProperties(
1506 : const uno::Reference< ucb::XCommandEnvironment > & )
1507 : {
1508 : static const beans::Property aGenericProperties[] =
1509 : {
1510 : beans::Property( OUString( "IsDocument" ),
1511 0 : -1, cppu::UnoType<bool>::get(),
1512 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1513 : beans::Property( OUString( "IsFolder" ),
1514 0 : -1, cppu::UnoType<bool>::get(),
1515 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1516 : beans::Property( OUString( "Title" ),
1517 0 : -1, cppu::UnoType<OUString>::get(),
1518 : beans::PropertyAttribute::BOUND ),
1519 : beans::Property( OUString( "ObjectId" ),
1520 0 : -1, cppu::UnoType<OUString>::get(),
1521 : beans::PropertyAttribute::BOUND ),
1522 : beans::Property( OUString( "TitleOnServer" ),
1523 0 : -1, cppu::UnoType<OUString>::get(),
1524 : beans::PropertyAttribute::BOUND ),
1525 : beans::Property( OUString( "IsReadOnly" ),
1526 0 : -1, cppu::UnoType<bool>::get(),
1527 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1528 : beans::Property( OUString( "DateCreated" ),
1529 0 : -1, cppu::UnoType<util::DateTime>::get(),
1530 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1531 : beans::Property( OUString( "DateModified" ),
1532 0 : -1, cppu::UnoType<util::DateTime>::get(),
1533 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1534 : beans::Property( OUString( "Size" ),
1535 0 : -1, cppu::UnoType<sal_Int64>::get(),
1536 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1537 : beans::Property( OUString( "CreatableContentsInfo" ),
1538 0 : -1, cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
1539 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1540 : beans::Property( OUString( "MediaType" ),
1541 0 : -1, cppu::UnoType<OUString>::get(),
1542 : beans::PropertyAttribute::BOUND ),
1543 : beans::Property( OUString( "CmisProperties" ),
1544 0 : -1, cppu::UnoType<uno::Sequence< document::CmisProperty>>::get(),
1545 : beans::PropertyAttribute::BOUND ),
1546 : beans::Property( OUString( "IsVersionable" ),
1547 0 : -1, cppu::UnoType<bool>::get(),
1548 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1549 : beans::Property( OUString( "CanCheckOut" ),
1550 0 : -1, cppu::UnoType<bool>::get(),
1551 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1552 : beans::Property( OUString( "CanCancelCheckOut" ),
1553 0 : -1, cppu::UnoType<bool>::get(),
1554 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1555 : beans::Property( OUString( "CanCheckIn" ),
1556 0 : -1, cppu::UnoType<bool>::get(),
1557 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1558 0 : };
1559 :
1560 0 : const int nProps = SAL_N_ELEMENTS(aGenericProperties);
1561 0 : return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
1562 : }
1563 :
1564 0 : uno::Sequence< ucb::CommandInfo > Content::getCommands(
1565 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1566 : {
1567 : static const ucb::CommandInfo aCommandInfoTable[] =
1568 : {
1569 : // Required commands
1570 : ucb::CommandInfo
1571 : ( OUString( "getCommandInfo" ),
1572 0 : -1, cppu::UnoType<void>::get() ),
1573 : ucb::CommandInfo
1574 : ( OUString( "getPropertySetInfo" ),
1575 0 : -1, cppu::UnoType<void>::get() ),
1576 : ucb::CommandInfo
1577 : ( OUString( "getPropertyValues" ),
1578 0 : -1, cppu::UnoType<uno::Sequence< beans::Property >>::get() ),
1579 : ucb::CommandInfo
1580 : ( OUString( "setPropertyValues" ),
1581 0 : -1, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() ),
1582 :
1583 : // Optional standard commands
1584 : ucb::CommandInfo
1585 : ( OUString( "delete" ),
1586 0 : -1, cppu::UnoType<bool>::get() ),
1587 : ucb::CommandInfo
1588 : ( OUString( "insert" ),
1589 0 : -1, cppu::UnoType<ucb::InsertCommandArgument2>::get() ),
1590 : ucb::CommandInfo
1591 : ( OUString( "open" ),
1592 0 : -1, cppu::UnoType<ucb::OpenCommandArgument2>::get() ),
1593 :
1594 : // Mandatory CMIS-only commands
1595 0 : ucb::CommandInfo ( OUString( "checkout" ), -1, cppu::UnoType<void>::get() ),
1596 0 : ucb::CommandInfo ( OUString( "cancelCheckout" ), -1, cppu::UnoType<void>::get() ),
1597 : ucb::CommandInfo ( OUString( "checkIn" ), -1,
1598 0 : cppu::UnoType<ucb::TransferInfo>::get() ),
1599 0 : ucb::CommandInfo ( OUString( "updateProperties" ), -1, cppu::UnoType<void>::get() ),
1600 : ucb::CommandInfo
1601 : ( OUString( "getAllVersions" ),
1602 0 : -1, cppu::UnoType<uno::Sequence< document::CmisVersion >>::get() ),
1603 :
1604 :
1605 : // Folder Only, omitted if not a folder
1606 : ucb::CommandInfo
1607 : ( OUString( "transfer" ),
1608 0 : -1, cppu::UnoType<ucb::TransferInfo>::get() ),
1609 : ucb::CommandInfo
1610 : ( OUString( "createNewContent" ),
1611 0 : -1, cppu::UnoType<ucb::ContentInfo>::get() )
1612 0 : };
1613 :
1614 0 : const int nProps = SAL_N_ELEMENTS( aCommandInfoTable );
1615 0 : return uno::Sequence< ucb::CommandInfo >(aCommandInfoTable, isFolder( xEnv ) ? nProps : nProps - 2);
1616 : }
1617 :
1618 0 : OUString Content::getParentURL( )
1619 : {
1620 : SAL_INFO( "ucb.ucp.cmis", "Content::getParentURL()" );
1621 0 : OUString parentUrl = "/";
1622 0 : if ( m_sObjectPath == "/" )
1623 0 : return parentUrl;
1624 : else
1625 : {
1626 0 : INetURLObject aUrl( m_sURL );
1627 0 : if ( aUrl.getSegmentCount( ) > 0 )
1628 : {
1629 0 : URL aCmisUrl( m_sURL );
1630 0 : aUrl.removeSegment( );
1631 0 : aCmisUrl.setObjectPath( aUrl.GetURLPath( INetURLObject::DECODE_WITH_CHARSET ) );
1632 0 : parentUrl = aCmisUrl.asString( );
1633 0 : }
1634 : }
1635 0 : return parentUrl;
1636 : }
1637 :
1638 0 : XTYPEPROVIDER_COMMON_IMPL( Content );
1639 :
1640 0 : void SAL_CALL Content::acquire() throw()
1641 : {
1642 0 : ContentImplHelper::acquire();
1643 0 : }
1644 :
1645 0 : void SAL_CALL Content::release() throw()
1646 : {
1647 0 : ContentImplHelper::release();
1648 0 : }
1649 :
1650 0 : uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException, std::exception )
1651 : {
1652 0 : uno::Any aRet = cppu::queryInterface( rType, static_cast< ucb::XContentCreator * >( this ) );
1653 0 : return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1654 : }
1655 :
1656 0 : OUString SAL_CALL Content::getImplementationName() throw( uno::RuntimeException, std::exception )
1657 : {
1658 0 : return OUString("com.sun.star.comp.CmisContent");
1659 : }
1660 :
1661 0 : uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
1662 : throw( uno::RuntimeException, std::exception )
1663 : {
1664 0 : uno::Sequence< OUString > aSNS( 1 );
1665 0 : aSNS.getArray()[ 0 ] = "com.sun.star.ucb.CmisContent";
1666 0 : return aSNS;
1667 : }
1668 :
1669 0 : OUString SAL_CALL Content::getContentType() throw( uno::RuntimeException, std::exception )
1670 : {
1671 0 : OUString sRet;
1672 : try
1673 : {
1674 0 : sRet = isFolder( uno::Reference< ucb::XCommandEnvironment >() )
1675 : ? OUString(CMIS_FOLDER_TYPE)
1676 0 : : OUString(CMIS_FILE_TYPE);
1677 : }
1678 0 : catch (const uno::RuntimeException&)
1679 : {
1680 0 : throw;
1681 : }
1682 0 : catch (const uno::Exception& e)
1683 : {
1684 0 : uno::Any a(cppu::getCaughtException());
1685 : throw lang::WrappedTargetRuntimeException(
1686 0 : "wrapped Exception " + e.Message,
1687 0 : uno::Reference<uno::XInterface>(), a);
1688 : }
1689 0 : return sRet;
1690 : }
1691 :
1692 0 : uno::Any SAL_CALL Content::execute(
1693 : const ucb::Command& aCommand,
1694 : sal_Int32 /*CommandId*/,
1695 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1696 : throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException, std::exception )
1697 : {
1698 : SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand.Name );
1699 0 : uno::Any aRet;
1700 :
1701 0 : if ( aCommand.Name == "getPropertyValues" )
1702 : {
1703 0 : uno::Sequence< beans::Property > Properties;
1704 0 : if ( !( aCommand.Argument >>= Properties ) )
1705 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1706 0 : aRet <<= getPropertyValues( Properties, xEnv );
1707 : }
1708 0 : else if ( aCommand.Name == "getPropertySetInfo" )
1709 0 : aRet <<= getPropertySetInfo( xEnv, false );
1710 0 : else if ( aCommand.Name == "getCommandInfo" )
1711 0 : aRet <<= getCommandInfo( xEnv, false );
1712 0 : else if ( aCommand.Name == "open" )
1713 : {
1714 0 : ucb::OpenCommandArgument2 aOpenCommand;
1715 0 : if ( !( aCommand.Argument >>= aOpenCommand ) )
1716 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1717 0 : aRet = open( aOpenCommand, xEnv );
1718 : }
1719 0 : else if ( aCommand.Name == "transfer" )
1720 : {
1721 0 : ucb::TransferInfo transferArgs;
1722 0 : if ( !( aCommand.Argument >>= transferArgs ) )
1723 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1724 0 : transfer( transferArgs, xEnv );
1725 : }
1726 0 : else if ( aCommand.Name == "setPropertyValues" )
1727 : {
1728 0 : uno::Sequence< beans::PropertyValue > aProperties;
1729 0 : if ( !( aCommand.Argument >>= aProperties ) || !aProperties.getLength() )
1730 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1731 0 : aRet <<= setPropertyValues( aProperties, xEnv );
1732 : }
1733 0 : else if (aCommand.Name == "createNewContent"
1734 0 : && isFolder( xEnv ) )
1735 : {
1736 0 : ucb::ContentInfo arg;
1737 0 : if ( !( aCommand.Argument >>= arg ) )
1738 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1739 0 : aRet <<= createNewContent( arg );
1740 : }
1741 0 : else if ( aCommand.Name == "insert" )
1742 : {
1743 0 : ucb::InsertCommandArgument2 arg;
1744 0 : if ( !( aCommand.Argument >>= arg ) )
1745 : {
1746 0 : ucb::InsertCommandArgument insertArg;
1747 0 : if ( !( aCommand.Argument >>= insertArg ) )
1748 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1749 :
1750 0 : arg.Data = insertArg.Data;
1751 0 : arg.ReplaceExisting = insertArg.ReplaceExisting;
1752 : }
1753 : // store the document id
1754 0 : m_sObjectId = arg.DocumentId;
1755 0 : insert( arg.Data, arg.ReplaceExisting, arg.MimeType, xEnv );
1756 : }
1757 0 : else if ( aCommand.Name == "delete" )
1758 : {
1759 : try
1760 : {
1761 0 : if ( !isFolder( xEnv ) )
1762 : {
1763 0 : getObject( xEnv )->remove( );
1764 : }
1765 : else
1766 : {
1767 0 : libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get() );
1768 0 : if (folder)
1769 0 : folder->removeTree( );
1770 : }
1771 : }
1772 0 : catch ( const libcmis::Exception& e )
1773 : {
1774 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1775 : ucbhelper::cancelCommandExecution(
1776 : ucb::IOErrorCode_GENERAL,
1777 : uno::Sequence< uno::Any >( 0 ),
1778 : xEnv,
1779 0 : OUString::createFromAscii( e.what() ) );
1780 : }
1781 : }
1782 0 : else if ( aCommand.Name == "checkout" )
1783 : {
1784 0 : aRet <<= checkOut( xEnv );
1785 : }
1786 0 : else if ( aCommand.Name == "cancelCheckout" )
1787 : {
1788 0 : aRet <<= cancelCheckOut( xEnv );
1789 : }
1790 0 : else if ( aCommand.Name == "checkin" )
1791 : {
1792 0 : ucb::CheckinArgument aArg;
1793 0 : if ( !( aCommand.Argument >>= aArg ) )
1794 : {
1795 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv );
1796 : }
1797 0 : aRet <<= checkIn( aArg, xEnv );
1798 : }
1799 0 : else if ( aCommand.Name == "getAllVersions" )
1800 : {
1801 0 : aRet <<= getAllVersions( xEnv );
1802 : }
1803 0 : else if ( aCommand.Name == "updateProperties" )
1804 : {
1805 0 : updateProperties( aCommand.Argument, xEnv );
1806 : }
1807 : else
1808 : {
1809 : SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1810 :
1811 : ucbhelper::cancelCommandExecution
1812 : ( uno::makeAny( ucb::UnsupportedCommandException
1813 : ( OUString(),
1814 : static_cast< cppu::OWeakObject * >( this ) ) ),
1815 0 : xEnv );
1816 : }
1817 :
1818 0 : return aRet;
1819 : }
1820 :
1821 0 : void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException, std::exception )
1822 : {
1823 : SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1824 : // TODO Implement me
1825 0 : }
1826 :
1827 0 : uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1828 : throw( uno::RuntimeException, std::exception )
1829 : {
1830 0 : return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() );
1831 : }
1832 :
1833 0 : uno::Reference< ucb::XContent > SAL_CALL Content::createNewContent(
1834 : const ucb::ContentInfo& Info ) throw( uno::RuntimeException, std::exception )
1835 : {
1836 : bool create_document;
1837 :
1838 0 : if ( Info.Type == CMIS_FILE_TYPE )
1839 0 : create_document = true;
1840 0 : else if ( Info.Type == CMIS_FOLDER_TYPE )
1841 0 : create_document = false;
1842 : else
1843 : {
1844 : SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1845 0 : return uno::Reference< ucb::XContent >();
1846 : }
1847 :
1848 0 : OUString sParentURL = m_xIdentifier->getContentIdentifier();
1849 0 : URL aParentURL( sParentURL );
1850 :
1851 : // Set the parent URL for the transient objects
1852 0 : uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(sParentURL));
1853 :
1854 : try
1855 : {
1856 0 : return new ::cmis::Content( m_xContext, m_pProvider, xId, !create_document );
1857 : }
1858 0 : catch ( ucb::ContentCreationException & )
1859 : {
1860 0 : return uno::Reference< ucb::XContent >();
1861 0 : }
1862 : }
1863 :
1864 0 : uno::Sequence< uno::Type > SAL_CALL Content::getTypes() throw( uno::RuntimeException, std::exception )
1865 : {
1866 : try
1867 : {
1868 0 : if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
1869 : {
1870 : static cppu::OTypeCollection aFolderCollection
1871 0 : (CPPU_TYPE_REF( lang::XTypeProvider ),
1872 0 : CPPU_TYPE_REF( lang::XServiceInfo ),
1873 0 : CPPU_TYPE_REF( lang::XComponent ),
1874 0 : CPPU_TYPE_REF( ucb::XContent ),
1875 0 : CPPU_TYPE_REF( ucb::XCommandProcessor ),
1876 0 : CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1877 0 : CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1878 0 : CPPU_TYPE_REF( beans::XPropertyContainer ),
1879 0 : CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1880 0 : CPPU_TYPE_REF( container::XChild ),
1881 0 : CPPU_TYPE_REF( ucb::XContentCreator ) );
1882 0 : return aFolderCollection.getTypes();
1883 : }
1884 : }
1885 0 : catch (const uno::RuntimeException&)
1886 : {
1887 0 : throw;
1888 : }
1889 0 : catch (const uno::Exception& e)
1890 : {
1891 0 : uno::Any a(cppu::getCaughtException());
1892 : throw lang::WrappedTargetRuntimeException(
1893 0 : "wrapped Exception " + e.Message,
1894 0 : uno::Reference<uno::XInterface>(), a);
1895 : }
1896 :
1897 : static cppu::OTypeCollection aFileCollection
1898 0 : (CPPU_TYPE_REF( lang::XTypeProvider ),
1899 0 : CPPU_TYPE_REF( lang::XServiceInfo ),
1900 0 : CPPU_TYPE_REF( lang::XComponent ),
1901 0 : CPPU_TYPE_REF( ucb::XContent ),
1902 0 : CPPU_TYPE_REF( ucb::XCommandProcessor ),
1903 0 : CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1904 0 : CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1905 0 : CPPU_TYPE_REF( beans::XPropertyContainer ),
1906 0 : CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1907 0 : CPPU_TYPE_REF( container::XChild ) );
1908 :
1909 0 : return aFileCollection.getTypes();
1910 : }
1911 :
1912 0 : uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo(
1913 : const uno::Reference< ucb::XCommandEnvironment >& xEnv)
1914 : throw( uno::RuntimeException )
1915 : {
1916 : try
1917 : {
1918 0 : if ( isFolder( xEnv ) )
1919 : {
1920 0 : uno::Sequence< ucb::ContentInfo > seq(2);
1921 :
1922 : // Minimum set of props we really need
1923 0 : uno::Sequence< beans::Property > props( 1 );
1924 0 : props[0] = beans::Property(
1925 : OUString("Title"),
1926 : -1,
1927 0 : cppu::UnoType<OUString>::get(),
1928 0 : beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND );
1929 :
1930 : // file
1931 0 : seq[0].Type = CMIS_FILE_TYPE;
1932 0 : seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
1933 0 : ucb::ContentInfoAttribute::KIND_DOCUMENT );
1934 0 : seq[0].Properties = props;
1935 :
1936 : // folder
1937 0 : seq[1].Type = CMIS_FOLDER_TYPE;
1938 0 : seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1939 0 : seq[1].Properties = props;
1940 :
1941 0 : return seq;
1942 : }
1943 : }
1944 0 : catch (const uno::RuntimeException&)
1945 : {
1946 0 : throw;
1947 : }
1948 0 : catch (const uno::Exception& e)
1949 : {
1950 0 : uno::Any a(cppu::getCaughtException());
1951 : throw lang::WrappedTargetRuntimeException(
1952 0 : "wrapped Exception " + e.Message,
1953 0 : uno::Reference<uno::XInterface>(), a);
1954 : }
1955 0 : return uno::Sequence< ucb::ContentInfo >();
1956 : }
1957 :
1958 0 : list< uno::Reference< ucb::XContent > > Content::getChildren( )
1959 : {
1960 0 : list< uno::Reference< ucb::XContent > > results;
1961 : SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL );
1962 :
1963 0 : libcmis::FolderPtr pFolder = boost::dynamic_pointer_cast< libcmis::Folder >( getObject( uno::Reference< ucb::XCommandEnvironment >() ) );
1964 0 : if ( 0 != pFolder )
1965 : {
1966 : // Get the children from pObject
1967 : try
1968 : {
1969 0 : vector< libcmis::ObjectPtr > children = pFolder->getChildren( );
1970 :
1971 : // Loop over the results
1972 0 : for ( vector< libcmis::ObjectPtr >::iterator it = children.begin();
1973 0 : it != children.end(); ++it )
1974 : {
1975 : // TODO Cache the objects
1976 :
1977 0 : URL aUrl( m_sURL );
1978 0 : OUString sPath( m_sObjectPath );
1979 0 : if ( !sPath.endsWith("/") )
1980 0 : sPath += "/";
1981 0 : sPath += STD_TO_OUSTR( ( *it )->getName( ) );
1982 0 : OUString sId = STD_TO_OUSTR( ( *it )->getId( ) );
1983 0 : aUrl.setObjectId( sId );
1984 0 : aUrl.setObjectPath( sPath );
1985 0 : uno::Reference< ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( aUrl.asString( ) );
1986 0 : uno::Reference< ucb::XContent > xContent = new Content( m_xContext, m_pProvider, xId, *it );
1987 :
1988 0 : results.push_back( xContent );
1989 0 : }
1990 : }
1991 0 : catch ( const libcmis::Exception& e )
1992 : {
1993 : SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e.what() );
1994 : }
1995 : }
1996 :
1997 0 : return results;
1998 : }
1999 :
2000 0 : void Content::setCmisProperty(const std::string& rName, const std::string& rValue, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2001 : {
2002 0 : if ( getObjectType( xEnv ).get( ) )
2003 : {
2004 0 : map< string, libcmis::PropertyPtr >::iterator propIt = m_pObjectProps.find(rName);
2005 0 : vector< string > values;
2006 0 : values.push_back(rValue);
2007 :
2008 0 : if ( propIt == m_pObjectProps.end( ) && getObjectType( xEnv ).get( ) )
2009 : {
2010 0 : map< string, libcmis::PropertyTypePtr > propsTypes = getObjectType( xEnv )->getPropertiesTypes( );
2011 0 : map< string, libcmis::PropertyTypePtr >::iterator typeIt = propsTypes.find(rName);
2012 :
2013 0 : if ( typeIt != propsTypes.end( ) )
2014 : {
2015 0 : libcmis::PropertyTypePtr propType = typeIt->second;
2016 0 : libcmis::PropertyPtr property( new libcmis::Property( propType, values ) );
2017 0 : m_pObjectProps.insert(pair< string, libcmis::PropertyPtr >(rName, property));
2018 0 : }
2019 : }
2020 0 : else if ( propIt != m_pObjectProps.end( ) )
2021 : {
2022 0 : propIt->second->setValues( values );
2023 0 : }
2024 : }
2025 0 : }
2026 0 : }
2027 :
2028 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|