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