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 /*
25 * This file pinched from webdavdatasupplier (etc.)
26 * cut & paste + new getData impl. & collate ResultSet code.
27 */
28 #include <vector>
29 #include <osl/diagnose.h>
30 #include <com/sun/star/ucb/OpenMode.hpp>
31 #include <ucbhelper/contentidentifier.hxx>
32 #include <ucbhelper/providerhelper.hxx>
33
34 #include "gvfs_directory.hxx"
35
36 #include <libgnomevfs/gnome-vfs-utils.h>
37 #include <libgnomevfs/gnome-vfs-directory.h>
38
39 using namespace com::sun::star;
40 using namespace gvfs;
41
42 // DynamicResultSet Implementation.
43
DynamicResultSet(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr,const rtl::Reference<Content> & rxContent,const ucb::OpenCommandArgument2 & rCommand,const uno::Reference<ucb::XCommandEnvironment> & rxEnv)44 DynamicResultSet::DynamicResultSet(
45 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
46 const rtl::Reference< Content >& rxContent,
47 const ucb::OpenCommandArgument2& rCommand,
48 const uno::Reference< ucb::XCommandEnvironment >& rxEnv )
49 : ResultSetImplHelper( rxSMgr, rCommand ),
50 m_xContent( rxContent ),
51 m_xEnv( rxEnv )
52 {
53 }
initStatic()54 void DynamicResultSet::initStatic()
55 {
56 m_xResultSet1
57 = new ::ucbhelper::ResultSet( m_xSMgr,
58 m_aCommand.Properties,
59 new DataSupplier( m_xSMgr,
60 m_xContent,
61 m_aCommand.Mode ),
62 m_xEnv );
63 }
initDynamic()64 void DynamicResultSet::initDynamic()
65 {
66 initStatic();
67 m_xResultSet2 = m_xResultSet1;
68 }
69
70 //=========================================================================
71
72
73 // DataSupplier Implementation.
74
75
76
77 struct ResultListEntry
78 {
79 rtl::OUString aId;
80 uno::Reference< ucb::XContentIdentifier > xId;
81 uno::Reference< ucb::XContent > xContent;
82 uno::Reference< sdbc::XRow > xRow;
83 GnomeVFSFileInfo aInfo;
84
ResultListEntryResultListEntry85 ResultListEntry( const GnomeVFSFileInfo *fileInfo)
86 {
87 gnome_vfs_file_info_copy (&aInfo, fileInfo);
88 }
89
~ResultListEntryResultListEntry90 ~ResultListEntry()
91 {
92 gnome_vfs_file_info_clear (&aInfo);
93 }
94 };
95
96 //=========================================================================
97 //
98 // ResultList.
99 //
100 //=========================================================================
101
102 typedef std::vector< ResultListEntry* > ResultList;
103
104 //=========================================================================
105 //
106 // struct DataSupplier_Impl.
107 //
108 //=========================================================================
109
110 struct gvfs::DataSupplier_Impl
111 {
112 osl::Mutex m_aMutex;
113 ResultList m_aResults;
114 rtl::Reference< Content > m_xContent;
115 uno::Reference< lang::XMultiServiceFactory > m_xSMgr;
116 sal_Int32 m_nOpenMode;
117 sal_Bool m_bCountFinal;
118
DataSupplier_Implgvfs::DataSupplier_Impl119 DataSupplier_Impl(
120 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
121 const rtl::Reference< Content >& rContent,
122 sal_Int32 nOpenMode )
123 : m_xContent( rContent ), m_xSMgr( rxSMgr ),
124 m_nOpenMode( nOpenMode ), m_bCountFinal( sal_False ) {}
~DataSupplier_Implgvfs::DataSupplier_Impl125 ~DataSupplier_Impl()
126 {
127 ResultList::const_iterator it = m_aResults.begin();
128 ResultList::const_iterator end = m_aResults.end();
129
130 while ( it != end )
131 {
132 delete (*it);
133 it++;
134 }
135 }
136 };
137
DataSupplier(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr,const rtl::Reference<Content> & rContent,sal_Int32 nOpenMode)138 DataSupplier::DataSupplier(
139 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
140 const rtl::Reference< Content >& rContent,
141 sal_Int32 nOpenMode )
142 : m_pImpl( new DataSupplier_Impl( rxSMgr, rContent, nOpenMode ) )
143 {
144 }
145
146 //=========================================================================
147 // virtual
~DataSupplier()148 DataSupplier::~DataSupplier()
149 {
150 delete m_pImpl;
151 }
152
153 // virtual
queryContentIdentifierString(sal_uInt32 nIndex)154 rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
155 {
156 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
157
158 if ( nIndex < m_pImpl->m_aResults.size() ) {
159 rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
160 if ( aId.getLength() ) // cached
161 return aId;
162 }
163
164 if ( getResult( nIndex ) ) {
165 rtl::OUString aId = m_pImpl->m_xContent->getOUURI();
166
167 char *escaped_name;
168 escaped_name = gnome_vfs_escape_string( m_pImpl->m_aResults[ nIndex ]->aInfo.name );
169
170 if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
171 aId += rtl::OUString::createFromAscii( "/" );
172
173 aId += rtl::OUString::createFromAscii( escaped_name );
174
175 g_free( escaped_name );
176
177 m_pImpl->m_aResults[ nIndex ]->aId = aId;
178 return aId;
179 }
180
181 return rtl::OUString();
182 }
183
184 // virtual
185 uno::Reference< ucb::XContentIdentifier >
queryContentIdentifier(sal_uInt32 nIndex)186 DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
187 {
188 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
189
190 if ( nIndex < m_pImpl->m_aResults.size() ) {
191 uno::Reference< ucb::XContentIdentifier > xId
192 = m_pImpl->m_aResults[ nIndex ]->xId;
193 if ( xId.is() ) // Already cached.
194 return xId;
195 }
196
197 rtl::OUString aId = queryContentIdentifierString( nIndex );
198 if ( aId.getLength() ) {
199 uno::Reference< ucb::XContentIdentifier > xId
200 = new ::ucbhelper::ContentIdentifier( aId );
201 m_pImpl->m_aResults[ nIndex ]->xId = xId;
202 return xId;
203 }
204
205 return uno::Reference< ucb::XContentIdentifier >();
206 }
207
208 // virtual
209 uno::Reference< ucb::XContent >
queryContent(sal_uInt32 nIndex)210 DataSupplier::queryContent( sal_uInt32 nIndex )
211 {
212 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
213
214 if ( nIndex < m_pImpl->m_aResults.size() ) {
215 uno::Reference< ucb::XContent > xContent
216 = m_pImpl->m_aResults[ nIndex ]->xContent;
217 if ( xContent.is() ) // Already cached.
218 return xContent;
219 }
220
221 uno::Reference< ucb::XContentIdentifier > xId
222 = queryContentIdentifier( nIndex );
223 if ( xId.is() ) {
224 try
225 {
226 // FIXME:
227 // It would be really nice to propagate this information
228 // to the Content, but we can't then register it with the
229 // ContentProvider, and the ucbhelper hinders here.
230 uno::Reference< ucb::XContent > xContent
231 = m_pImpl->m_xContent->getProvider()->queryContent( xId );
232 m_pImpl->m_aResults[ nIndex ]->xContent = xContent;
233 return xContent;
234
235 }
236 catch ( ucb::IllegalIdentifierException& ) {
237 }
238 }
239 return uno::Reference< ucb::XContent >();
240 }
241
242 // virtual
getResult(sal_uInt32 nIndex)243 sal_Bool DataSupplier::getResult( sal_uInt32 nIndex )
244 {
245 osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
246
247 if ( m_pImpl->m_aResults.size() > nIndex ) // Result already present.
248 return sal_True;
249
250 if ( getData() && m_pImpl->m_aResults.size() > nIndex )
251 return sal_True;
252
253 return sal_False;
254 }
255
256 // virtual
totalCount()257 sal_uInt32 DataSupplier::totalCount()
258 {
259 getData();
260
261 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
262
263 return m_pImpl->m_aResults.size();
264 }
265
266 // virtual
currentCount()267 sal_uInt32 DataSupplier::currentCount()
268 {
269 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
270 return m_pImpl->m_aResults.size();
271 }
272
273 // virtual
isCountFinal()274 sal_Bool DataSupplier::isCountFinal()
275 {
276 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
277 return m_pImpl->m_bCountFinal;
278 }
279
280 // virtual
queryPropertyValues(sal_uInt32 nIndex)281 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues( sal_uInt32 nIndex )
282 {
283 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
284
285 if ( nIndex < m_pImpl->m_aResults.size() ) {
286 uno::Reference< sdbc::XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
287 if ( xRow.is() ) // Already cached.
288 return xRow;
289 }
290
291 if ( getResult( nIndex ) ) {
292 // Inefficient - but we can't create xContent's sensibly
293 // nor can we do the property code sensibly cleanly staticaly.
294 Content *pContent = static_cast< ::gvfs::Content * >(queryContent( nIndex ).get());
295
296 uno::Reference< sdbc::XRow > xRow =
297 pContent->getPropertyValues( getResultSet()->getProperties(),
298 getResultSet()->getEnvironment() );
299
300 m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
301
302 return xRow;
303 }
304
305 return uno::Reference< sdbc::XRow >();
306 }
307
308 // virtual
releasePropertyValues(sal_uInt32 nIndex)309 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
310 {
311 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
312
313 if ( nIndex < m_pImpl->m_aResults.size() )
314 m_pImpl->m_aResults[ nIndex ]->xRow = uno::Reference< sdbc::XRow >();
315 }
316
317 // virtual
close()318 void DataSupplier::close()
319 {
320 }
321
322 // virtual
validate()323 void DataSupplier::validate()
324 throw( ucb::ResultSetException )
325 {
326 }
327
getData()328 sal_Bool DataSupplier::getData()
329 {
330 osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
331
332 if ( !m_pImpl->m_bCountFinal ) {
333 GnomeVFSResult result;
334 GnomeVFSDirectoryHandle *dirHandle = NULL;
335
336 {
337 Authentication aAuth( getResultSet()->getEnvironment() );
338 char *uri = m_pImpl->m_xContent->getURI();
339 result = gnome_vfs_directory_open
340 ( &dirHandle, uri, GNOME_VFS_FILE_INFO_DEFAULT );
341
342 if (result != GNOME_VFS_OK) {
343 #ifdef DEBUG
344 g_warning ("Failed open of '%s' with '%s'",
345 uri, gnome_vfs_result_to_string( result ));
346 #endif
347 g_free( uri );
348 return sal_False;
349 }
350
351 g_free( uri );
352 }
353
354 GnomeVFSFileInfo* fileInfo = gnome_vfs_file_info_new ();
355
356 while ((result = gnome_vfs_directory_read_next (dirHandle, fileInfo)) == GNOME_VFS_OK) {
357 if( fileInfo->name && fileInfo->name[0] == '.' &&
358 ( fileInfo->name[1] == '\0' ||
359 ( fileInfo->name[1] == '.' && fileInfo->name[2] == '\0' ) ) )
360 continue;
361
362 switch ( m_pImpl->m_nOpenMode ) {
363 case ucb::OpenMode::FOLDERS:
364 if ( !(fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) ||
365 fileInfo->type != GNOME_VFS_FILE_TYPE_DIRECTORY )
366 continue;
367 break;
368
369 case ucb::OpenMode::DOCUMENTS:
370 if ( !(fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) ||
371 fileInfo->type != GNOME_VFS_FILE_TYPE_REGULAR )
372 continue;
373 break;
374
375 case ucb::OpenMode::ALL:
376 default:
377 break;
378 }
379
380 m_pImpl->m_aResults.push_back( new ResultListEntry( fileInfo ) );
381 }
382
383 gnome_vfs_file_info_unref (fileInfo);
384
385 #ifdef DEBUG
386 g_warning ("Got %d directory entries", result);
387 #endif
388
389 m_pImpl->m_bCountFinal = sal_True;
390
391 // Callback possible, because listeners may be informed!
392 aGuard.clear();
393 getResultSet()->rowCountFinal();
394
395 if (result != GNOME_VFS_ERROR_EOF) {
396 #ifdef DEBUG
397 g_warning( "Failed read_next '%s'",
398 gnome_vfs_result_to_string( result ) );
399 #endif
400 return sal_False;
401 }
402
403 result = gnome_vfs_directory_close (dirHandle);
404 if (result != GNOME_VFS_OK) {
405 #ifdef DEBUG
406 g_warning( "Failed close '%s'",
407 gnome_vfs_result_to_string( result ) );
408 #endif
409 return sal_False;
410 }
411 }
412
413 return sal_True;
414 }
415
416
417
418