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