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 <com/sun/star/beans/PropertyAttribute.hpp>
11 : #include <com/sun/star/beans/PropertyValue.hpp>
12 : #include <com/sun/star/beans/XPropertySetInfo.hpp>
13 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
14 : #include <com/sun/star/task/XInteractionHandler.hpp>
15 : #include <com/sun/star/ucb/XCommandInfo.hpp>
16 : #include <com/sun/star/ucb/XDynamicResultSet.hpp>
17 : #include <com/sun/star/ucb/XProgressHandler.hpp>
18 :
19 : #include <comphelper/processfactory.hxx>
20 : #include <config_oauth2.h>
21 : #include <rtl/uri.hxx>
22 : #include <ucbhelper/cancelcommandexecution.hxx>
23 : #include <ucbhelper/commandenvironment.hxx>
24 : #include <ucbhelper/contentidentifier.hxx>
25 : #include <ucbhelper/propertyvalueset.hxx>
26 : #include <ucbhelper/proxydecider.hxx>
27 :
28 : #include "auth_provider.hxx"
29 : #include "certvalidation_handler.hxx"
30 : #include "cmis_content.hxx"
31 : #include "cmis_provider.hxx"
32 : #include "cmis_repo_content.hxx"
33 : #include "cmis_resultset.hxx"
34 :
35 : #define OUSTR_TO_STDSTR(s) string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
36 : #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
37 :
38 : using namespace com::sun::star;
39 : using namespace std;
40 :
41 : namespace cmis
42 : {
43 0 : RepoContent::RepoContent( const uno::Reference< uno::XComponentContext >& rxContext,
44 : ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier,
45 : vector< libcmis::RepositoryPtr > aRepos )
46 : throw ( ucb::ContentCreationException )
47 : : ContentImplHelper( rxContext, pProvider, Identifier ),
48 : m_pProvider( pProvider ),
49 0 : m_aURL( Identifier->getContentIdentifier( ) ),
50 : m_sRepositoryId( ),
51 0 : m_aRepositories( aRepos )
52 : {
53 : // Split the URL into bits
54 0 : OUString sURL = m_xIdentifier->getContentIdentifier( );
55 : SAL_INFO( "ucb.ucp.cmis", "RepoContent::RepoContent() " << sURL );
56 :
57 0 : m_sRepositoryId = m_aURL.getObjectPath( );
58 0 : m_sRepositoryId.startsWith("/", &m_sRepositoryId);
59 0 : }
60 :
61 0 : RepoContent::~RepoContent()
62 : {
63 0 : }
64 :
65 0 : uno::Any RepoContent::getBadArgExcept()
66 : {
67 : return uno::makeAny( lang::IllegalArgumentException(
68 : OUString("Wrong argument type!"),
69 0 : static_cast< cppu::OWeakObject * >( this ), -1) );
70 : }
71 :
72 0 : uno::Reference< sdbc::XRow > RepoContent::getPropertyValues(
73 : const uno::Sequence< beans::Property >& rProperties,
74 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
75 : {
76 0 : rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
77 :
78 : sal_Int32 nProps;
79 : const beans::Property* pProps;
80 :
81 0 : nProps = rProperties.getLength();
82 0 : pProps = rProperties.getConstArray();
83 :
84 0 : for( sal_Int32 n = 0; n < nProps; ++n )
85 : {
86 0 : const beans::Property& rProp = pProps[ n ];
87 :
88 : try
89 : {
90 0 : if ( rProp.Name == "IsDocument" )
91 : {
92 0 : xRow->appendBoolean( rProp, false );
93 : }
94 0 : else if ( rProp.Name == "IsFolder" )
95 : {
96 0 : xRow->appendBoolean( rProp, true );
97 : }
98 0 : else if ( rProp.Name == "Title" )
99 : {
100 0 : xRow->appendString( rProp, STD_TO_OUSTR( getRepository( xEnv )->getName( ) ) );
101 : }
102 0 : else if ( rProp.Name == "IsReadOnly" )
103 : {
104 0 : xRow->appendBoolean( rProp, true );
105 : }
106 : else
107 : {
108 0 : xRow->appendVoid( rProp );
109 : SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp.Name );
110 : }
111 : }
112 0 : catch (const libcmis::Exception&)
113 : {
114 0 : xRow->appendVoid( rProp );
115 : }
116 : }
117 :
118 0 : return uno::Reference< sdbc::XRow >( xRow.get() );
119 : }
120 :
121 0 : void RepoContent::getRepositories( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
122 : {
123 : // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
124 0 : ucbhelper::InternetProxyDecider aProxyDecider( m_xContext );
125 0 : INetURLObject aBindingUrl( m_aURL.getBindingUrl( ) );
126 : const ucbhelper::InternetProxyServer& rProxy = aProxyDecider.getProxy(
127 0 : INetURLObject::GetScheme( aBindingUrl.GetProtocol( ) ), aBindingUrl.GetHost(), aBindingUrl.GetPort() );
128 0 : OUString sProxy = rProxy.aName;
129 0 : if ( rProxy.nPort > 0 )
130 0 : sProxy += ":" + OUString::number( rProxy.nPort );
131 0 : libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy ), string(), string(), string() );
132 :
133 0 : if ( m_aRepositories.empty() )
134 : {
135 : // Set the SSL Validation handler
136 : libcmis::CertValidationHandlerPtr certHandler(
137 0 : new CertValidationHandler( xEnv, m_xContext, aBindingUrl.GetHost( ) ) );
138 0 : libcmis::SessionFactory::setCertificateValidationHandler( certHandler );
139 :
140 : // Get the auth credentials
141 0 : AuthProvider authProvider( xEnv, m_xIdentifier->getContentIdentifier( ), m_aURL.getBindingUrl( ) );
142 :
143 0 : string rUsername = OUSTR_TO_STDSTR( m_aURL.getUsername( ) );
144 0 : string rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );
145 0 : if ( authProvider.authenticationQuery( rUsername, rPassword ) )
146 : {
147 : try
148 : {
149 : // Create a session to get repositories
150 0 : libcmis::OAuth2DataPtr oauth2Data;
151 0 : if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
152 : oauth2Data.reset( new libcmis::OAuth2Data(
153 : GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
154 : GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
155 0 : GDRIVE_CLIENT_ID, GDRIVE_CLIENT_SECRET ) );
156 0 : if ( m_aURL.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL ) )
157 : oauth2Data.reset( new libcmis::OAuth2Data(
158 : ALFRESCO_CLOUD_AUTH_URL, ALFRESCO_CLOUD_TOKEN_URL,
159 : ALFRESCO_CLOUD_SCOPE, ALFRESCO_CLOUD_REDIRECT_URI,
160 0 : ALFRESCO_CLOUD_CLIENT_ID, ALFRESCO_CLOUD_CLIENT_SECRET ) );
161 :
162 : libcmis::Session* session = libcmis::SessionFactory::createSession(
163 0 : OUSTR_TO_STDSTR( m_aURL.getBindingUrl( ) ),
164 0 : rUsername, rPassword, "", false, oauth2Data );
165 0 : if (session == NULL )
166 : ucbhelper::cancelCommandExecution(
167 : ucb::IOErrorCode_INVALID_DEVICE,
168 : uno::Sequence< uno::Any >( 0 ),
169 : xEnv,
170 0 : OUString( ) );
171 0 : m_aRepositories = session->getRepositories( );
172 0 : delete session;
173 : }
174 0 : catch (const libcmis::Exception& e)
175 : {
176 : SAL_INFO( "ucb.ucp.cmis", "Error getting repositories: " << e.what() );
177 : }
178 : }
179 : else
180 : {
181 : // Throw user cancelled exception
182 : ucbhelper::cancelCommandExecution(
183 : ucb::IOErrorCode_ABORT,
184 : uno::Sequence< uno::Any >( 0 ),
185 : xEnv,
186 0 : OUString( "Authentication cancelled" ) );
187 0 : }
188 0 : }
189 0 : }
190 :
191 0 : libcmis::RepositoryPtr RepoContent::getRepository( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
192 : {
193 : // Ensure we have the repositories extracted
194 0 : getRepositories( xEnv );
195 :
196 0 : libcmis::RepositoryPtr repo;
197 :
198 0 : if ( !m_sRepositoryId.isEmpty() )
199 : {
200 0 : for ( vector< libcmis::RepositoryPtr >::iterator it = m_aRepositories.begin( );
201 0 : it != m_aRepositories.end( ) && NULL == repo.get( ); ++it )
202 : {
203 0 : if ( STD_TO_OUSTR( ( *it )->getId( ) ) == m_sRepositoryId )
204 0 : repo = *it;
205 : }
206 : }
207 : else
208 0 : repo = m_aRepositories.front( );
209 0 : return repo;
210 : }
211 :
212 0 : uno::Sequence< beans::Property > RepoContent::getProperties(
213 : const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
214 : {
215 : static const beans::Property aGenericProperties[] =
216 : {
217 : beans::Property( OUString( "IsDocument" ),
218 0 : -1, getCppuBooleanType(),
219 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
220 : beans::Property( OUString( "IsFolder" ),
221 0 : -1, getCppuBooleanType(),
222 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
223 : beans::Property( OUString( "Title" ),
224 0 : -1, getCppuType( static_cast< const OUString * >( 0 ) ),
225 : beans::PropertyAttribute::BOUND ),
226 : beans::Property( OUString( "IsReadOnly" ),
227 0 : -1, getCppuBooleanType(),
228 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
229 0 : };
230 :
231 0 : const int nProps = SAL_N_ELEMENTS(aGenericProperties);
232 0 : return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
233 : }
234 :
235 0 : uno::Sequence< ucb::CommandInfo > RepoContent::getCommands(
236 : const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
237 : {
238 : static const ucb::CommandInfo aCommandInfoTable[] =
239 : {
240 : // Required commands
241 : ucb::CommandInfo
242 : ( OUString( "getCommandInfo" ),
243 0 : -1, getCppuVoidType() ),
244 : ucb::CommandInfo
245 : ( OUString( "getPropertySetInfo" ),
246 0 : -1, getCppuVoidType() ),
247 : ucb::CommandInfo
248 : ( OUString( "getPropertyValues" ),
249 0 : -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
250 : ucb::CommandInfo
251 : ( OUString( "setPropertyValues" ),
252 0 : -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
253 :
254 : // Optional standard commands
255 : ucb::CommandInfo
256 : ( OUString( "open" ),
257 0 : -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
258 0 : };
259 :
260 0 : const int nProps = SAL_N_ELEMENTS(aCommandInfoTable);
261 0 : return uno::Sequence< ucb::CommandInfo >(aCommandInfoTable, nProps );
262 : }
263 :
264 0 : OUString RepoContent::getParentURL( )
265 : {
266 0 : OUString sRet;
267 :
268 : SAL_INFO( "ucb.ucp.cmis", "RepoContent::getParentURL()" );
269 :
270 : // TODO Implement me
271 :
272 0 : return sRet;
273 : }
274 :
275 0 : XTYPEPROVIDER_COMMON_IMPL( RepoContent );
276 :
277 0 : void SAL_CALL RepoContent::acquire() throw()
278 : {
279 0 : ContentImplHelper::acquire();
280 0 : }
281 :
282 0 : void SAL_CALL RepoContent::release() throw()
283 : {
284 0 : ContentImplHelper::release();
285 0 : }
286 :
287 0 : uno::Any SAL_CALL RepoContent::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException, std::exception )
288 : {
289 0 : return ContentImplHelper::queryInterface(rType);
290 : }
291 :
292 0 : OUString SAL_CALL RepoContent::getImplementationName() throw( uno::RuntimeException, std::exception )
293 : {
294 0 : return OUString("com.sun.star.comp.CmisRepoContent");
295 : }
296 :
297 0 : uno::Sequence< OUString > SAL_CALL RepoContent::getSupportedServiceNames()
298 : throw( uno::RuntimeException, std::exception )
299 : {
300 0 : uno::Sequence< OUString > aSNS( 1 );
301 0 : aSNS.getArray()[ 0 ] = "com.sun.star.ucb.Content";
302 0 : return aSNS;
303 : }
304 :
305 0 : OUString SAL_CALL RepoContent::getContentType() throw( uno::RuntimeException, std::exception )
306 : {
307 0 : return OUString( CMIS_REPO_TYPE );
308 : }
309 :
310 0 : uno::Any SAL_CALL RepoContent::execute(
311 : const ucb::Command& aCommand,
312 : sal_Int32 /*CommandId*/,
313 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
314 : throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException, std::exception )
315 : {
316 : SAL_INFO( "ucb.ucp.cmis", "RepoContent::execute( ) - " << aCommand.Name );
317 :
318 0 : uno::Any aRet;
319 :
320 0 : if ( aCommand.Name == "getPropertyValues" )
321 : {
322 0 : uno::Sequence< beans::Property > Properties;
323 0 : if ( !( aCommand.Argument >>= Properties ) )
324 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
325 0 : aRet <<= getPropertyValues( Properties, xEnv );
326 : }
327 0 : else if ( aCommand.Name == "getPropertySetInfo" )
328 0 : aRet <<= getPropertySetInfo( xEnv, false );
329 0 : else if ( aCommand.Name == "getCommandInfo" )
330 0 : aRet <<= getCommandInfo( xEnv, false );
331 0 : else if ( aCommand.Name == "open" )
332 : {
333 0 : ucb::OpenCommandArgument2 aOpenCommand;
334 0 : if ( !( aCommand.Argument >>= aOpenCommand ) )
335 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
336 0 : const ucb::OpenCommandArgument2& rOpenCommand = aOpenCommand;
337 :
338 0 : getRepositories( xEnv );
339 : uno::Reference< ucb::XDynamicResultSet > xSet
340 0 : = new DynamicResultSet(m_xContext, this, rOpenCommand, xEnv );
341 0 : aRet <<= xSet;
342 : }
343 : else
344 : {
345 : SAL_INFO( "ucb.ucp.cmis", "Command not allowed" );
346 : }
347 :
348 0 : return aRet;
349 : }
350 :
351 0 : void SAL_CALL RepoContent::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException, std::exception )
352 : {
353 : SAL_INFO( "ucb.ucp.cmis", "TODO - RepoContent::abort()" );
354 : // TODO Implement me
355 0 : }
356 :
357 0 : uno::Sequence< uno::Type > SAL_CALL RepoContent::getTypes() throw( uno::RuntimeException, std::exception )
358 : {
359 : static cppu::OTypeCollection aFolderCollection
360 0 : (CPPU_TYPE_REF( lang::XTypeProvider ),
361 0 : CPPU_TYPE_REF( lang::XServiceInfo ),
362 0 : CPPU_TYPE_REF( lang::XComponent ),
363 0 : CPPU_TYPE_REF( ucb::XContent ),
364 0 : CPPU_TYPE_REF( ucb::XCommandProcessor ),
365 0 : CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
366 0 : CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
367 0 : CPPU_TYPE_REF( beans::XPropertyContainer ),
368 0 : CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
369 0 : CPPU_TYPE_REF( container::XChild ) );
370 0 : return aFolderCollection.getTypes();
371 : }
372 :
373 0 : list< uno::Reference< ucb::XContent > > RepoContent::getChildren( )
374 : {
375 0 : list< uno::Reference< ucb::XContent > > result;
376 :
377 : // TODO Cache the results somehow
378 : SAL_INFO( "ucb.ucp.cmis", "RepoContent::getChildren" );
379 :
380 0 : if ( m_sRepositoryId.isEmpty( ) )
381 : {
382 0 : for ( vector< libcmis::RepositoryPtr >::iterator it = m_aRepositories.begin( );
383 0 : it != m_aRepositories.end(); ++it )
384 : {
385 0 : URL aUrl( m_aURL );
386 0 : aUrl.setObjectPath( STD_TO_OUSTR( ( *it )->getId( ) ) );
387 :
388 0 : uno::Reference< ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( aUrl.asString( ) );
389 0 : uno::Reference< ucb::XContent > xContent = new RepoContent( m_xContext, m_pProvider, xId, m_aRepositories );
390 :
391 0 : result.push_back( xContent );
392 0 : }
393 : }
394 : else
395 : {
396 : // Return the repository root as child
397 0 : OUString sUrl;
398 : OUString sEncodedBinding = rtl::Uri::encode(
399 0 : m_aURL.getBindingUrl( ) + "#" + m_sRepositoryId,
400 : rtl_UriCharClassRelSegment,
401 : rtl_UriEncodeKeepEscapes,
402 0 : RTL_TEXTENCODING_UTF8 );
403 0 : sUrl = "vnd.libreoffice.cmis://" + sEncodedBinding;
404 :
405 0 : uno::Reference< ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( sUrl );
406 0 : uno::Reference< ucb::XContent > xContent = new Content( m_xContext, m_pProvider, xId );
407 :
408 0 : result.push_back( xContent );
409 : }
410 0 : return result;
411 : }
412 0 : }
413 :
414 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|