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