1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32 								TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 #include <osl/diagnose.h>
37 #include <com/sun/star/ucb/OpenMode.hpp>
38 #include <ucbhelper/contentidentifier.hxx>
39 #include <ucbhelper/providerhelper.hxx>
40 #include "webdavdatasupplier.hxx"
41 #include "webdavcontent.hxx"
42 #include "ContentProperties.hxx"
43 #ifndef _WEBDAV_SESSION_HXX
44 #include "DAVSession.hxx"
45 #endif
46 #include "NeonUri.hxx"
47 
48 using namespace com::sun::star;
49 using namespace webdav_ucp;
50 
51 namespace webdav_ucp
52 {
53 
54 //=========================================================================
55 //
56 // struct ResultListEntry.
57 //
58 //=========================================================================
59 
60 struct ResultListEntry
61 {
62     rtl::OUString                             aId;
63     uno::Reference< ucb::XContentIdentifier > xId;
64     uno::Reference< ucb::XContent >           xContent;
65     uno::Reference< sdbc::XRow >              xRow;
66     const ContentProperties*                  pData;
67 
68 	ResultListEntry( const ContentProperties* pEntry ) : pData( pEntry ) {};
69  	~ResultListEntry() { delete pData; }
70 };
71 
72 //=========================================================================
73 //
74 // ResultList.
75 //
76 //=========================================================================
77 
78 typedef std::vector< ResultListEntry* > ResultList;
79 
80 //=========================================================================
81 //
82 // struct DataSupplier_Impl.
83 //
84 //=========================================================================
85 
86 struct DataSupplier_Impl
87 {
88     osl::Mutex                                   m_aMutex;
89     ResultList                                   m_aResults;
90     rtl::Reference< Content >                    m_xContent;
91     uno::Reference< lang::XMultiServiceFactory > m_xSMgr;
92     sal_Int32                                    m_nOpenMode;
93     sal_Bool                                     m_bCountFinal;
94     sal_Bool                                     m_bThrowException;
95 
96     DataSupplier_Impl(
97                 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
98                 const rtl::Reference< Content >& rContent,
99                 sal_Int32 nOpenMode )
100     : m_xContent( rContent ), m_xSMgr( rxSMgr ), m_nOpenMode( nOpenMode ),
101       m_bCountFinal( sal_False ), m_bThrowException( sal_False ) {}
102 	~DataSupplier_Impl();
103 };
104 
105 //=========================================================================
106 DataSupplier_Impl::~DataSupplier_Impl()
107 {
108 	ResultList::const_iterator it  = m_aResults.begin();
109 	ResultList::const_iterator end = m_aResults.end();
110 
111 	while ( it != end )
112 	{
113 		delete (*it);
114 		it++;
115 	}
116 }
117 
118 }
119 
120 //=========================================================================
121 //=========================================================================
122 //
123 // DataSupplier Implementation.
124 //
125 //=========================================================================
126 //=========================================================================
127 
128 DataSupplier::DataSupplier(
129             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
130             const rtl::Reference< Content >& rContent,
131             sal_Int32 nOpenMode )
132 : m_pImpl( new DataSupplier_Impl( rxSMgr, rContent, nOpenMode ) )
133 {
134 }
135 
136 //=========================================================================
137 // virtual
138 DataSupplier::~DataSupplier()
139 {
140 	delete m_pImpl;
141 }
142 
143 //=========================================================================
144 // virtual
145 rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
146 {
147 	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
148 
149 	if ( nIndex < m_pImpl->m_aResults.size() )
150 	{
151         rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
152 		if ( aId.getLength() )
153 		{
154 			// Already cached.
155 			return aId;
156 		}
157 	}
158 
159 	if ( getResult( nIndex ) )
160 	{
161         rtl::OUString aId = m_pImpl->m_xContent->getResourceAccess().getURL();
162 
163 		const ContentProperties& props
164 							= *( m_pImpl->m_aResults[ nIndex ]->pData );
165 
166 		if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
167             aId += rtl::OUString::createFromAscii( "/" );
168 
169         aId += props.getEscapedTitle();
170 
171         if ( props.isTrailingSlash() )
172             aId += rtl::OUString::createFromAscii( "/" );
173 
174 		m_pImpl->m_aResults[ nIndex ]->aId = aId;
175 		return aId;
176 	}
177     return rtl::OUString();
178 }
179 
180 //=========================================================================
181 // virtual
182 uno::Reference< ucb::XContentIdentifier >
183 DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
184 {
185 	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
186 
187 	if ( nIndex < m_pImpl->m_aResults.size() )
188 	{
189         uno::Reference< ucb::XContentIdentifier > xId
190             = m_pImpl->m_aResults[ nIndex ]->xId;
191 		if ( xId.is() )
192 		{
193 			// Already cached.
194 			return xId;
195 		}
196 	}
197 
198     rtl::OUString aId = queryContentIdentifierString( nIndex );
199 	if ( aId.getLength() )
200 	{
201         uno::Reference< ucb::XContentIdentifier > xId
202             = new ::ucbhelper::ContentIdentifier( aId );
203 		m_pImpl->m_aResults[ nIndex ]->xId = xId;
204 		return xId;
205 	}
206     return uno::Reference< ucb::XContentIdentifier >();
207 }
208 
209 //=========================================================================
210 // virtual
211 uno::Reference< ucb::XContent >
212 DataSupplier::queryContent( sal_uInt32 nIndex )
213 {
214 	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
215 
216 	if ( nIndex < m_pImpl->m_aResults.size() )
217 	{
218         uno::Reference< ucb::XContent > xContent
219             = m_pImpl->m_aResults[ nIndex ]->xContent;
220 		if ( xContent.is() )
221 		{
222 			// Already cached.
223 			return xContent;
224 		}
225 	}
226 
227     uno::Reference< ucb::XContentIdentifier > xId
228         = queryContentIdentifier( nIndex );
229 	if ( xId.is() )
230 	{
231 		try
232 		{
233             uno::Reference< ucb::XContent > xContent
234 				= m_pImpl->m_xContent->getProvider()->queryContent( xId );
235 			m_pImpl->m_aResults[ nIndex ]->xContent = xContent;
236 			return xContent;
237 
238 		}
239         catch ( ucb::IllegalIdentifierException& )
240 		{
241 		}
242 	}
243     return uno::Reference< ucb::XContent >();
244 }
245 
246 //=========================================================================
247 // virtual
248 sal_Bool DataSupplier::getResult( sal_uInt32 nIndex )
249 {
250 	osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
251 
252 	if ( m_pImpl->m_aResults.size() > nIndex )
253 	{
254 		// Result already present.
255 		return sal_True;
256 	}
257 
258 	// Obtain values...
259 	if ( getData() )
260 	{
261 		if ( m_pImpl->m_aResults.size() > nIndex )
262 		{
263 			// Result already present.
264 			return sal_True;
265 		}
266 	}
267 
268 	return sal_False;
269 }
270 
271 //=========================================================================
272 // virtual
273 sal_uInt32 DataSupplier::totalCount()
274 {
275   // Obtain values...
276   getData();
277 
278   return m_pImpl->m_aResults.size();
279 }
280 
281 //=========================================================================
282 // virtual
283 sal_uInt32 DataSupplier::currentCount()
284 {
285 	return m_pImpl->m_aResults.size();
286 }
287 
288 //=========================================================================
289 // virtual
290 sal_Bool DataSupplier::isCountFinal()
291 {
292 	return m_pImpl->m_bCountFinal;
293 }
294 
295 //=========================================================================
296 // virtual
297 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues(
298                                                     sal_uInt32 nIndex  )
299 {
300 	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
301 
302 	if ( nIndex < m_pImpl->m_aResults.size() )
303 	{
304         uno::Reference< sdbc::XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
305 		if ( xRow.is() )
306 		{
307 			// Already cached.
308 			return xRow;
309 		}
310 	}
311 
312 	if ( getResult( nIndex ) )
313 	{
314         uno::Reference< sdbc::XRow > xRow
315             = Content::getPropertyValues(
316                 m_pImpl->m_xSMgr,
317                 getResultSet()->getProperties(),
318                 *(m_pImpl->m_aResults[ nIndex ]->pData),
319                 rtl::Reference< ::ucbhelper::ContentProviderImplHelper >(
320                     m_pImpl->m_xContent->getProvider().get() ),
321                 queryContentIdentifierString( nIndex ) );
322 		m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
323 		return xRow;
324 	}
325 
326     return uno::Reference< sdbc::XRow >();
327 }
328 
329 //=========================================================================
330 // virtual
331 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
332 {
333 	osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
334 
335 	if ( nIndex < m_pImpl->m_aResults.size() )
336         m_pImpl->m_aResults[ nIndex ]->xRow = uno::Reference< sdbc::XRow >();
337 }
338 
339 //=========================================================================
340 // virtual
341 void DataSupplier::close()
342 {
343 }
344 
345 //=========================================================================
346 // virtual
347 void DataSupplier::validate()
348     throw( ucb::ResultSetException )
349 {
350     if ( m_pImpl->m_bThrowException )
351         throw ucb::ResultSetException();
352 }
353 
354 //=========================================================================
355 sal_Bool DataSupplier::getData()
356 {
357 	osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
358 
359 	if ( !m_pImpl->m_bCountFinal )
360 	{
361         std::vector< rtl::OUString > propertyNames;
362 		ContentProperties::UCBNamesToDAVNames(
363 						getResultSet()->getProperties(), propertyNames );
364 
365 		// Append "resourcetype", if not already present. It's value is
366 		// needed to get a valid ContentProperties::pIsFolder value, which
367 		// is needed for OpenMode handling.
368 
369         std::vector< rtl::OUString >::const_iterator it
370             = propertyNames.begin();
371         std::vector< rtl::OUString >::const_iterator end
372             = propertyNames.end();
373 
374 		while ( it != end )
375 		{
376 			if ( (*it).equals( DAVProperties::RESOURCETYPE ) )
377 				break;
378 
379 			it++;
380 		}
381 
382 		if ( it == end )
383 			propertyNames.push_back( DAVProperties::RESOURCETYPE );
384 
385 		std::vector< DAVResource > resources;
386 		try
387 		{
388             // propfind depth 1, get property values for parent AND for each
389             // child
390     		m_pImpl->m_xContent->getResourceAccess()
391 				.PROPFIND( DAVONE,
392 						   propertyNames,
393 						   resources,
394 						   getResultSet()->getEnvironment() );
395   		}
396   		catch ( DAVException & )
397 		{
398 //    		OSL_ENSURE( sal_False, "PROPFIND : DAVException" );
399             m_pImpl->m_bThrowException = sal_True;
400   		}
401 
402         if ( !m_pImpl->m_bThrowException )
403         {
404             try
405             {
406                 NeonUri aURI(
407                     m_pImpl->m_xContent->getResourceAccess().getURL() );
408                 rtl::OUString aPath = aURI.GetPath();
409 
410                 if ( aPath.getStr()[ aPath.getLength() - 1 ]
411                      == sal_Unicode( '/' ) )
412                     aPath = aPath.copy( 0, aPath.getLength() - 1 );
413 
414                 aPath = NeonUri::unescape( aPath );
415                 bool bFoundParent = false;
416 
417                 for ( sal_uInt32 n = 0; n < resources.size(); ++n )
418                 {
419                     const DAVResource & rRes = resources[ n ];
420 
421                     // Filter parent, which is contained somewhere(!) in
422                     // the vector.
423                     if ( !bFoundParent )
424                     {
425                         try
426                         {
427                             NeonUri aCurrURI( rRes.uri );
428                             rtl::OUString aCurrPath = aCurrURI.GetPath();
429                             if ( aCurrPath.getStr()[
430                                      aCurrPath.getLength() - 1 ]
431                                  == sal_Unicode( '/' ) )
432                                 aCurrPath
433                                     = aCurrPath.copy(
434                                         0,
435                                         aCurrPath.getLength() - 1 );
436 
437                             aCurrPath = NeonUri::unescape( aCurrPath );
438                             if ( aPath == aCurrPath )
439                             {
440                                 bFoundParent = true;
441                                 continue;
442                             }
443                         }
444                         catch ( DAVException const & )
445                         {
446                             // do nothing, ignore error. continue.
447                         }
448                     }
449 
450                     ContentProperties* pContentProperties
451                         = new ContentProperties( rRes );
452 
453                     // Check resource against open mode.
454                     switch ( m_pImpl->m_nOpenMode )
455                     {
456                     case ucb::OpenMode::FOLDERS:
457                         {
458                             sal_Bool bFolder = sal_False;
459 
460                             const uno::Any & rValue
461                                 = pContentProperties->getValue(
462                                     rtl::OUString(
463                                         RTL_CONSTASCII_USTRINGPARAM(
464                                             "IsFolder" ) ) );
465                             rValue >>= bFolder;
466 
467                             if ( !bFolder )
468                                 continue;
469 
470                             break;
471                         }
472 
473                     case ucb::OpenMode::DOCUMENTS:
474                         {
475                             sal_Bool bDocument = sal_False;
476 
477                             const uno::Any & rValue
478                                 = pContentProperties->getValue(
479                                     rtl::OUString(
480                                         RTL_CONSTASCII_USTRINGPARAM(
481                                             "IsDocument" ) ) );
482                             rValue >>= bDocument;
483 
484                             if ( !bDocument )
485                                 continue;
486 
487                             break;
488                         }
489 
490                     case ucb::OpenMode::ALL:
491                     default:
492                         break;
493                     }
494 
495                     m_pImpl->m_aResults.push_back(
496                         new ResultListEntry( pContentProperties ) );
497                 }
498             }
499             catch ( DAVException const & )
500             {
501             }
502         }
503 
504   		m_pImpl->m_bCountFinal = sal_True;
505 
506 		// Callback possible, because listeners may be informed!
507 		aGuard.clear();
508 		getResultSet()->rowCountFinal();
509 	}
510     return !m_pImpl->m_bThrowException;
511 }
512 
513