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 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include "osl/time.h"
29 #include <osl/diagnose.h>
30
31 #include "osl/doublecheckedlocking.h"
32
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
36 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
37 #include <com/sun/star/io/XActiveDataSink.hpp>
38 #include <com/sun/star/io/XOutputStream.hpp>
39 #include <com/sun/star/lang/IllegalAccessException.hpp>
40 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
41 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
42 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
43 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
44 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
45 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
46 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
47 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
48 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
49 #include <com/sun/star/ucb/NameClash.hpp>
50 #include <com/sun/star/ucb/NameClashException.hpp>
51 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
52 #include <com/sun/star/ucb/OpenMode.hpp>
53 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
56 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
57 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
58 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
59 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
60 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
61 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
62 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
63 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
64 #include <com/sun/star/ucb/NameClashException.hpp>
65 #include <ucbhelper/contentidentifier.hxx>
66 #include <ucbhelper/propertyvalueset.hxx>
67 #include <ucbhelper/interactionrequest.hxx>
68 #include <ucbhelper/cancelcommandexecution.hxx>
69 #include <ucbhelper/simpleauthenticationrequest.hxx>
70
71 const int TRANSFER_BUFFER_SIZE = 65536;
72
73 /*
74 * NB. Name escaping is done only for URIs
75 * the 'Title' property is unescaped on set/get
76 */
77 #include <libgnomevfs/gnome-vfs-utils.h>
78 #include <libgnomevfs/gnome-vfs-result.h>
79 #include <libgnomevfs/gnome-vfs-standard-callbacks.h>
80 extern "C" { // missing in the header: doh.
81 # include <libgnomevfs/gnome-vfs-module-callback.h>
82 }
83
84 #include "gvfs_content.hxx"
85 #include "gvfs_provider.hxx"
86 #include "gvfs_directory.hxx"
87 #include "gvfs_stream.hxx"
88
89 using namespace gvfs;
90 using namespace com::sun::star;
91
92 #define CLEAR_INFO(info) memset((info), 0, sizeof ((info)[0]))
93
94
95 static char *
OUStringToGnome(const rtl::OUString & str)96 OUStringToGnome( const rtl::OUString &str )
97 {
98 rtl::OString aTempStr = rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 );
99 return g_strdup( aTempStr.getStr() );
100 }
101
102 static rtl::OUString
GnomeToOUString(const char * utf8_str)103 GnomeToOUString( const char *utf8_str)
104 {
105 if (!utf8_str)
106 return rtl::OUString();
107 else
108 return rtl::OUString( utf8_str, strlen( utf8_str ), RTL_TEXTENCODING_UTF8 );
109 }
110
111
Content(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier)112 Content::Content(
113 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
114 ContentProvider* pProvider,
115 const uno::Reference< ucb::XContentIdentifier >& Identifier)
116 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
117 m_pProvider( pProvider ),
118 m_bTransient( sal_False )
119 {
120 CLEAR_INFO (&m_info);
121 #ifdef DEBUG
122 g_warning ("New Content ('%s')", getURI());
123 #endif
124 }
125
Content(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier,sal_Bool IsFolder)126 Content::Content(
127 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
128 ContentProvider * pProvider,
129 const uno::Reference< ucb::XContentIdentifier >& Identifier,
130 sal_Bool IsFolder)
131 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
132 m_pProvider( pProvider ),
133 m_bTransient( sal_True )
134 {
135 CLEAR_INFO (&m_info);
136
137 #ifdef DEBUG
138 g_warning ("New Transient content ('%s') (%d)", getURI(), IsFolder);
139 #endif
140 // m_info.name = FIXME: set name ?
141 m_info.valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE;
142 m_info.type = IsFolder ? GNOME_VFS_FILE_TYPE_DIRECTORY :
143 GNOME_VFS_FILE_TYPE_REGULAR;
144 }
145
146 // virtual
~Content()147 Content::~Content()
148 {
149 gnome_vfs_file_info_clear( &m_info );
150 }
151
152 //
153 // XInterface methods.
154 //
155
acquire()156 void SAL_CALL Content::acquire()
157 throw( )
158 {
159 ContentImplHelper::acquire();
160 }
release()161 void SAL_CALL Content::release()
162 throw( )
163 {
164 ContentImplHelper::release();
165 }
queryInterface(const uno::Type & rType)166 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
167 {
168 // Note: isFolder may require network activities! So call it only
169 // if it is really necessary!!!
170 uno::Any aRet = cppu::queryInterface( rType,
171 static_cast< ucb::XContentCreator * >( this ) );
172 if ( aRet.hasValue() )
173 return isFolder( uno::Reference< ucb::XCommandEnvironment >() )
174 ? aRet : uno::Any();
175 else
176 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
177 }
178
179 //
180 // XTypeProvider methods.
181 //
182
183 XTYPEPROVIDER_COMMON_IMPL( Content );
184
getTypes()185 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
186 {
187 static cppu::OTypeCollection *pFolderCollection = NULL;
188 static cppu::OTypeCollection *pFileCollection = NULL;
189
190 if (!pFolderCollection) {
191 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
192
193 if (!pFolderCollection) {
194 static cppu::OTypeCollection aFolderCollection
195 (CPPU_TYPE_REF( lang::XTypeProvider ),
196 CPPU_TYPE_REF( lang::XServiceInfo ),
197 CPPU_TYPE_REF( lang::XComponent ),
198 CPPU_TYPE_REF( ucb::XContent ),
199 CPPU_TYPE_REF( ucb::XCommandProcessor ),
200 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
201 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
202 CPPU_TYPE_REF( beans::XPropertyContainer ),
203 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
204 CPPU_TYPE_REF( container::XChild ),
205 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
206 static cppu::OTypeCollection aFileCollection
207 (CPPU_TYPE_REF( lang::XTypeProvider ),
208 CPPU_TYPE_REF( lang::XServiceInfo ),
209 CPPU_TYPE_REF( lang::XComponent ),
210 CPPU_TYPE_REF( ucb::XContent ),
211 CPPU_TYPE_REF( ucb::XCommandProcessor ),
212 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
213 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
214 CPPU_TYPE_REF( beans::XPropertyContainer ),
215 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
216 CPPU_TYPE_REF( container::XChild ) );
217
218 pFolderCollection = &aFolderCollection;
219 pFileCollection = &aFileCollection;
220 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
221 }
222 }
223 else {
224 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
225 }
226
227 if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
228 return pFolderCollection->getTypes();
229 else
230 return pFileCollection->getTypes();
231 }
232
233 //
234 // XServiceInfo methods.
235 //
236
getImplementationName()237 rtl::OUString SAL_CALL Content::getImplementationName()
238 {
239 return rtl::OUString::createFromAscii("com.sun.star.comp.GnomeVFSContent" );
240 }
241
getSupportedServiceNames()242 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
243 {
244 uno::Sequence< rtl::OUString > aSNS( 1 );
245 aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
246 "com.sun.star.ucb.GnomeVFSContent" );
247 return aSNS;
248 }
249
250 //
251 // XContent methods.
252 //
253
getContentType()254 rtl::OUString SAL_CALL Content::getContentType()
255 {
256 if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
257 return rtl::OUString::createFromAscii( GVFS_FOLDER_TYPE );
258 else
259 return rtl::OUString::createFromAscii( GVFS_FILE_TYPE );
260 }
261
262 //
263 // XCommandProcessor methods.
264 //
265
getBadArgExcept()266 uno::Any Content::getBadArgExcept()
267 {
268 return uno::makeAny( lang::IllegalArgumentException
269 ( rtl::OUString::createFromAscii( "Wrong argument type!" ),
270 static_cast< cppu::OWeakObject * >( this ),
271 -1 ) );
272 }
273
274 #include <stdio.h>
275
execute(const ucb::Command & aCommand,sal_Int32,const uno::Reference<ucb::XCommandEnvironment> & xEnv)276 uno::Any SAL_CALL Content::execute(
277 const ucb::Command& aCommand,
278 sal_Int32 /*CommandId*/,
279 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
280 {
281 uno::Any aRet;
282
283 #ifdef DEBUG
284 {
285 uno::Reference< task::XInteractionHandler > xIH;
286
287 if ( xEnv.is() )
288 xIH = xEnv->getInteractionHandler();
289 g_warning( "Execute command: '%s' with %s interaction env",
290 OUStringToGnome( aCommand.Name ),
291 xIH.is() ? "" : "NO" );
292 }
293 #endif
294
295 #define COMMAND_IS(cmd,name) ( (cmd).Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( name ) ) )
296
297 if ( COMMAND_IS( aCommand, "getPropertyValues" ) ) {
298 uno::Sequence< beans::Property > Properties;
299
300 if ( !( aCommand.Argument >>= Properties ) )
301 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
302
303 aRet <<= getPropertyValues( Properties, xEnv );
304
305 } else if ( COMMAND_IS( aCommand, "setPropertyValues" ) ) {
306 uno::Sequence< beans::PropertyValue > aProperties;
307
308 if ( !( aCommand.Argument >>= aProperties ) ||
309 !aProperties.getLength() )
310 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
311
312 aRet <<= setPropertyValues( aProperties, xEnv );
313
314 } else if ( COMMAND_IS( aCommand, "getPropertySetInfo" ) ) {
315 aRet <<= getPropertySetInfo( xEnv, sal_False );
316
317 } else if ( COMMAND_IS( aCommand, "getCommandInfo" ) ) {
318 aRet <<= getCommandInfo( xEnv, sal_False );
319
320 } else if ( COMMAND_IS( aCommand, "open" ) ) {
321 rtl::OUString str = m_xIdentifier->getContentIdentifier();
322 rtl::OString stra(
323 str.getStr(),
324 str.getLength(),
325 RTL_TEXTENCODING_UTF8);
326
327 ucb::OpenCommandArgument2 aOpenCommand;
328 if ( !( aCommand.Argument >>= aOpenCommand ) )
329 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
330
331 sal_Bool bOpenFolder =
332 ( ( aOpenCommand.Mode == ucb::OpenMode::ALL ) ||
333 ( aOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
334 ( aOpenCommand.Mode == ucb::OpenMode::DOCUMENTS ) );
335
336 if ( bOpenFolder && isFolder( xEnv ) ) {
337 uno::Reference< ucb::XDynamicResultSet > xSet
338 = new DynamicResultSet(m_xSMgr, this, aOpenCommand, xEnv );
339 aRet <<= xSet;
340
341 } else if ( aOpenCommand.Sink.is() ) {
342
343 if ( ( aOpenCommand.Mode
344 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
345 ( aOpenCommand.Mode
346 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) {
347 ucbhelper::cancelCommandExecution
348 ( uno::makeAny ( ucb::UnsupportedOpenModeException
349 ( rtl::OUString(),
350 static_cast< cppu::OWeakObject * >( this ),
351 sal_Int16( aOpenCommand.Mode ) ) ),
352 xEnv );
353 }
354 if ( !feedSink( aOpenCommand.Sink, xEnv ) ) {
355 // Note: aOpenCommand.Sink may contain an XStream
356 // implementation. Support for this type of
357 // sink is optional...
358 #ifdef DEBUG
359 g_warning ("Failed to load data from '%s'", getURI());
360 #endif
361 ucbhelper::cancelCommandExecution
362 ( uno::makeAny (ucb::UnsupportedDataSinkException
363 ( rtl::OUString(),
364 static_cast< cppu::OWeakObject * >( this ),
365 aOpenCommand.Sink ) ),
366 xEnv );
367 }
368 }
369 #ifdef DEBUG
370 else
371 g_warning ("Open falling through ...");
372 #endif
373
374 } else if ( COMMAND_IS( aCommand, "createNewContent" ) && isFolder( xEnv ) ) {
375 ucb::ContentInfo arg;
376 if ( !( aCommand.Argument >>= arg ) )
377 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
378
379 aRet <<= createNewContent( arg );
380
381 } else if ( COMMAND_IS( aCommand, "insert" ) ) {
382 ucb::InsertCommandArgument arg;
383 if ( !( aCommand.Argument >>= arg ) )
384 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
385
386 insert( arg.Data, arg.ReplaceExisting, xEnv );
387
388 } else if ( COMMAND_IS( aCommand, "delete" ) ) {
389
390 sal_Bool bDeletePhysical = sal_False;
391 aCommand.Argument >>= bDeletePhysical;
392
393 ::rtl::OString aURI = getOURI();
394 GnomeVFSResult result = gnome_vfs_unlink( aURI.getStr());
395
396 if (result != GNOME_VFS_OK)
397 cancelCommandExecution( result, xEnv, sal_True );
398
399 destroy( bDeletePhysical );
400
401 } else if ( COMMAND_IS( aCommand, "transfer" ) && isFolder( xEnv ) ) {
402 ucb::TransferInfo transferArgs;
403
404 if ( !( aCommand.Argument >>= transferArgs ) )
405 ucbhelper::cancelCommandExecution( getBadArgExcept(), xEnv );
406
407 transfer( transferArgs, xEnv );
408
409 } else { // Unsupported
410 #ifdef DEBUG
411 g_warning( "Unsupported command: '%s'",
412 OUStringToGnome( aCommand.Name ) );
413 #endif
414 ucbhelper::cancelCommandExecution
415 ( uno::makeAny( ucb::UnsupportedCommandException
416 ( rtl::OUString(),
417 static_cast< cppu::OWeakObject * >( this ) ) ),
418 xEnv );
419 }
420 #undef COMMAND_IS
421
422 return aRet;
423 }
424
abort(sal_Int32)425 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
426 {
427 // FIXME: we should use the GnomeVFSCancellation APIs here ...
428 }
429
430 //
431 // XContentCreator methods.
432 //
433
queryCreatableContentsInfo(const uno::Reference<ucb::XCommandEnvironment> & xEnv)434 uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo(
435 const uno::Reference< ucb::XCommandEnvironment >& xEnv)
436 {
437 if ( isFolder( xEnv ) )
438 {
439 uno::Sequence< ucb::ContentInfo > seq(2);
440
441 // Minimum set of props we really need
442 uno::Sequence< beans::Property > props( 1 );
443 props[0] = beans::Property(
444 rtl::OUString::createFromAscii( "Title" ),
445 -1,
446 getCppuType( static_cast< rtl::OUString* >( 0 ) ),
447 beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND );
448
449 // file
450 seq[0].Type = rtl::OUString::createFromAscii( GVFS_FILE_TYPE );
451 seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
452 ucb::ContentInfoAttribute::KIND_DOCUMENT );
453 seq[0].Properties = props;
454
455 // folder
456 seq[1].Type = rtl::OUString::createFromAscii( GVFS_FOLDER_TYPE );
457 seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
458 seq[1].Properties = props;
459
460 return seq;
461 }
462 else
463 {
464 return uno::Sequence< ucb::ContentInfo >();
465 }
466 }
467
queryCreatableContentsInfo()468 uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
469 {
470 return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() );
471 }
472
473 uno::Reference< ucb::XContent > SAL_CALL
createNewContent(const ucb::ContentInfo & Info)474 Content::createNewContent( const ucb::ContentInfo& Info )
475 {
476 bool create_document;
477 const char *name;
478
479 if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GVFS_FILE_TYPE ) ) )
480 create_document = true;
481 else if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GVFS_FOLDER_TYPE ) ) )
482 create_document = false;
483 else {
484 #ifdef DEBUG
485 g_warning( "Failed to create new content '%s'",
486 OUStringToGnome( Info.Type ) );
487 #endif
488 return uno::Reference< ucb::XContent >();
489 }
490
491 #ifdef DEBUG
492 g_warning( "createNewContent (%d)", (int) create_document );
493 #endif
494
495 rtl::OUString aURL = getOUURI();
496
497 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
498 aURL += rtl::OUString::createFromAscii( "/" );
499
500 name = create_document ? "[New_Content]" : "[New_Collection]";
501 // This looks problematic to me cf. webdav
502 aURL += rtl::OUString::createFromAscii( name );
503
504 uno::Reference< ucb::XContentIdentifier > xId
505 ( new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) );
506
507 try {
508 return new ::gvfs::Content( m_xSMgr, m_pProvider, xId, !create_document );
509 } catch ( ucb::ContentCreationException & ) {
510 return uno::Reference< ucb::XContent >();
511 }
512 }
513
getParentURL()514 rtl::OUString Content::getParentURL()
515 {
516 rtl::OUString aParentURL;
517 // <scheme>:// -> ""
518 // <scheme>://foo -> ""
519 // <scheme>://foo/ -> ""
520 // <scheme>://foo/bar -> <scheme>://foo/
521 // <scheme>://foo/bar/ -> <scheme>://foo/
522 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
523
524 rtl::OUString aURL = getOUURI();
525
526 sal_Int32 nPos = aURL.lastIndexOf( '/' );
527 if ( nPos == ( aURL.getLength() - 1 ) ) {
528 // Trailing slash found. Skip.
529 nPos = aURL.lastIndexOf( '/', nPos );
530 }
531
532 sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos );
533 if ( nPos1 != -1 )
534 nPos1 = aURL.lastIndexOf( '/', nPos1 );
535
536 if ( nPos1 != -1 )
537 aParentURL = rtl::OUString( aURL.copy( 0, nPos + 1 ) );
538
539 #ifdef DEBUG
540 g_warning ("getParentURL '%s' -> '%s'",
541 getURI(), rtl::OUStringToOString( aParentURL, RTL_TEXTENCODING_UTF8).getStr() );
542 #endif
543
544 return aParentURL;
545 }
546
547 static util::DateTime
getDateFromUnix(time_t t)548 getDateFromUnix (time_t t)
549 {
550 TimeValue tv;
551 tv.Nanosec = 0;
552 tv.Seconds = t;
553 oslDateTime dt;
554
555 if ( osl_getDateTimeFromTimeValue( &tv, &dt ) )
556 return util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours,
557 dt.Day, dt.Month, dt.Year);
558 else
559 return util::DateTime();
560 }
561
getPropertyValues(const uno::Sequence<beans::Property> & rProperties,const uno::Reference<ucb::XCommandEnvironment> & xEnv)562 uno::Reference< sdbc::XRow > Content::getPropertyValues(
563 const uno::Sequence< beans::Property >& rProperties,
564 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
565 {
566 int nProps;
567 GnomeVFSResult result;
568 uno::Sequence< beans::Property > allProperties;
569
570 if( ( result = getInfo( xEnv ) ) != GNOME_VFS_OK )
571 cancelCommandExecution( result, xEnv, sal_False );
572
573 const beans::Property* pProps;
574
575 if( rProperties.getLength() ) {
576 nProps = rProperties.getLength();
577 pProps = rProperties.getConstArray();
578 } else {
579 allProperties = getPropertySetInfo( xEnv )->getProperties();
580 nProps = allProperties.getLength();
581 pProps = allProperties.getConstArray();
582 }
583
584 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
585 = new ::ucbhelper::PropertyValueSet( m_xSMgr );
586
587 osl::Guard< osl::Mutex > aGuard( m_aMutex );
588 for( sal_Int32 n = 0; n < nProps; ++n ) {
589 const beans::Property& rProp = pProps[ n ];
590
591 if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) {
592 if (m_info.name && m_info.name[0] == '/')
593 g_warning ("Odd NFS title on item '%s' == '%s'",
594 getURI(), m_info.name);
595 xRow->appendString( rProp, GnomeToOUString( m_info.name ) );
596 }
597
598 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
599 xRow->appendString( rProp, getContentType () );
600
601 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) {
602 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE)
603 xRow->appendBoolean( rProp, ( m_info.type == GNOME_VFS_FILE_TYPE_REGULAR ||
604 m_info.type == GNOME_VFS_FILE_TYPE_UNKNOWN ) );
605 else
606 xRow->appendVoid( rProp );
607 }
608 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) {
609 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE)
610 xRow->appendBoolean( rProp, ( m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY ) );
611 else
612 xRow->appendVoid( rProp );
613 }
614 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) ) {
615
616 GnomeVFSFileInfo* fileInfo = gnome_vfs_file_info_new ();
617
618 ::rtl::OString aURI = getOURI();
619 gnome_vfs_get_file_info( aURI.getStr(), fileInfo,
620 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS );
621
622 if (fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_ACCESS) {
623 bool read_only = true;
624
625 if (fileInfo->permissions & GNOME_VFS_PERM_ACCESS_WRITABLE)
626 read_only = false;
627
628 xRow->appendBoolean( rProp, read_only );
629 } else
630 xRow->appendVoid( rProp );
631 gnome_vfs_file_info_unref (fileInfo);
632 }
633 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) {
634 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)
635 xRow->appendLong( rProp, m_info.size );
636 else
637 xRow->appendVoid( rProp );
638 }
639 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsHidden" ) ) )
640 xRow->appendBoolean( rProp, ( m_info.name && m_info.name[0] == '.' ) );
641
642 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsVolume" ) ) ||
643 rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsCompactDisk" ) ) )
644 xRow->appendBoolean( rProp, sal_False );
645
646 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) {
647 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_CTIME)
648 xRow->appendTimestamp( rProp, getDateFromUnix( m_info.ctime ) );
649 else
650 xRow->appendVoid( rProp );
651 }
652
653 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) {
654 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME)
655 xRow->appendTimestamp( rProp, getDateFromUnix( m_info.mtime ) );
656 else
657 xRow->appendVoid( rProp );
658 }
659
660 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) {
661 // We do this by sniffing in gnome-vfs; rather expensively.
662 #ifdef DEBUG
663 g_warning ("FIXME: Requested mime-type - an expensive op. indeed!");
664 #endif
665 xRow->appendVoid( rProp );
666 } else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
667 xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
668
669 else {
670 xRow->appendVoid( rProp );
671 }
672 }
673 #ifdef DEBUG
674 g_warning ("getPropertyValues on '%s' %d properties returned (of %d)",
675 getURI(), (int)xRow->getLength(), (int)nProps);
676 #endif
677
678 return uno::Reference< sdbc::XRow >( xRow.get() );
679 }
680
681 static lang::IllegalAccessException
getReadOnlyException(Content * ctnt)682 getReadOnlyException( Content *ctnt )
683 {
684 return lang::IllegalAccessException
685 ( rtl::OUString::createFromAscii( "Property is read-only!" ),
686 static_cast< cppu::OWeakObject * >( ctnt ) );
687 }
688
689 rtl::OUString
makeNewURL(const char *)690 Content::makeNewURL( const char */*newName*/ )
691 {
692 rtl::OUString aNewURL = getParentURL();
693 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
694 aNewURL += rtl::OUString::createFromAscii( "/" );
695
696 char *name = gnome_vfs_escape_string( m_info.name );
697 aNewURL += GnomeToOUString( name );
698 g_free( name );
699
700 return aNewURL;
701 }
702
703 // This is slightly complicated by needing to support either 'move' or 'setname'
704 GnomeVFSResult
doSetFileInfo(const GnomeVFSFileInfo * newInfo,GnomeVFSSetFileInfoMask setMask,const uno::Reference<ucb::XCommandEnvironment> &)705 Content::doSetFileInfo( const GnomeVFSFileInfo *newInfo,
706 GnomeVFSSetFileInfoMask setMask,
707 const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
708 {
709 GnomeVFSResult result = GNOME_VFS_OK;
710
711 g_assert (!m_bTransient);
712
713 ::rtl::OString aURI = getOURI();
714
715 osl::Guard< osl::Mutex > aGuard( m_aMutex );
716
717 // The simple approach:
718 if( setMask != GNOME_VFS_SET_FILE_INFO_NONE )
719 result = gnome_vfs_set_file_info // missed a const in the API there
720 ( aURI.getStr(), (GnomeVFSFileInfo *)newInfo, setMask );
721
722 if ( result == GNOME_VFS_ERROR_NOT_SUPPORTED &&
723 ( setMask & GNOME_VFS_SET_FILE_INFO_NAME ) ) {
724 // Try a move instead
725 #ifdef DEBUG
726 g_warning( "SetFileInfo not supported on '%s'", getURI() );
727 #endif
728
729 char *newURI = OUStringToGnome( makeNewURL( newInfo->name ) );
730
731 result = gnome_vfs_move( aURI.getStr(), newURI, FALSE);
732
733 g_free (newURI);
734 }
735
736 return result;
737 }
738
739
setPropertyValues(const uno::Sequence<beans::PropertyValue> & rValues,const uno::Reference<ucb::XCommandEnvironment> & xEnv)740 uno::Sequence< uno::Any > Content::setPropertyValues(
741 const uno::Sequence< beans::PropertyValue >& rValues,
742 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
743 {
744 rtl::OUString aNewTitle;
745 GnomeVFSFileInfo newInfo;
746 int setMask = GNOME_VFS_SET_FILE_INFO_NONE;
747
748 getInfo( xEnv );
749
750 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
751
752 gnome_vfs_file_info_copy( &newInfo, &m_info );
753
754 Authentication aAuth( xEnv );
755
756 int nChanged = 0, nTitlePos = 0;
757 uno::Sequence< uno::Any > aRet( rValues.getLength() );
758 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
759
760 beans::PropertyChangeEvent aEvent;
761 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
762 aEvent.Further = sal_False;
763 aEvent.PropertyHandle = -1;
764 // aEvent.PropertyName = fill in later ...
765 // aEvent.OldValue =
766 // aEvent.NewValue =
767
768 int nCount = rValues.getLength();
769 const beans::PropertyValue* pValues = rValues.getConstArray();
770
771 for ( sal_Int32 n = 0; n < nCount; ++n ) {
772 const beans::PropertyValue& rValue = pValues[ n ];
773
774 #ifdef DEBUG
775 g_warning( "Set prop '%s'", OUStringToGnome( rValue.Name ) );
776 #endif
777 if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ||
778 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ||
779 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ||
780 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ||
781 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ||
782 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
783 aRet[ n ] <<= getReadOnlyException( this );
784
785 else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) {
786 if ( rValue.Value >>= aNewTitle ) {
787 if ( aNewTitle.getLength() <= 0 )
788 aRet[ n ] <<= lang::IllegalArgumentException
789 ( rtl::OUString::createFromAscii( "Empty title not allowed!" ),
790 static_cast< cppu::OWeakObject * >( this ), -1 );
791 else {
792 char *newName = OUStringToGnome( aNewTitle );
793
794 if( !newName || !m_info.name || strcmp( newName, m_info.name ) ) {
795 #ifdef DEBUG
796 g_warning ("Set new name to '%s'", newName);
797 #endif
798
799 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
800 aEvent.OldValue = uno::makeAny( GnomeToOUString( newInfo.name ) );
801 aEvent.NewValue = uno::makeAny( aNewTitle );
802 aChanges.getArray()[ nChanged ] = aEvent;
803 nTitlePos = nChanged++;
804
805 newInfo.name = newName;
806 setMask |= GNOME_VFS_SET_FILE_INFO_NAME;
807 } else // same name
808 g_free (newName);
809 }
810 } else
811 aRet[ n ] <<= beans::IllegalTypeException
812 ( rtl::OUString::createFromAscii( "Property value has wrong type!" ),
813 static_cast< cppu::OWeakObject * >( this ) );
814
815 } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ||
816 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) {
817 // FIXME: should be able to set the timestamps
818 aRet[ n ] <<= getReadOnlyException( this );
819 } else {
820 #ifdef DEBUG
821 g_warning( "Unhandled property '%s'", OUStringToGnome( rValue.Name ) );
822 #endif
823 aRet[ n ] <<= getReadOnlyException( this );
824 }
825 }
826
827 GnomeVFSResult result = GNOME_VFS_OK;
828
829 if ( !m_bTransient &&
830 ( result = doSetFileInfo( &newInfo,
831 (GnomeVFSSetFileInfoMask) setMask,
832 xEnv ) ) != GNOME_VFS_OK ) {
833 for (int i = 0; i < nChanged; i++)
834 aRet[ i ] <<= mapVFSException( result, sal_True );
835
836 }
837
838 if ( result == GNOME_VFS_OK) {
839 gnome_vfs_file_info_copy( &m_info, &newInfo );
840
841 if ( setMask & GNOME_VFS_SET_FILE_INFO_NAME ) {
842 uno::Reference< ucb::XContentIdentifier > xNewId
843 = new ::ucbhelper::ContentIdentifier(
844 m_xSMgr, makeNewURL( newInfo.name ) );
845
846 aGuard.clear();
847 if (!exchangeIdentity( xNewId ) )
848 aRet[ nTitlePos ] <<= uno::Exception
849 ( rtl::OUString::createFromAscii( "Exchange failed!" ),
850 static_cast< cppu::OWeakObject * >( this ) );
851 }
852 }
853
854 gnome_vfs_file_info_clear( &newInfo );
855
856 if ( nChanged > 0 ) {
857 aGuard.clear();
858 aChanges.realloc( nChanged );
859 notifyPropertiesChange( aChanges );
860 }
861
862 return aRet;
863 }
864
queryChildren(ContentRefList & rChildren)865 void Content::queryChildren( ContentRefList& rChildren )
866 {
867 // Obtain a list with a snapshot of all currently instantiated contents
868 // from provider and extract the contents which are direct children
869 // of this content.
870
871 ::ucbhelper::ContentRefList aAllContents;
872 m_xProvider->queryExistingContents( aAllContents );
873
874 rtl::OUString aURL = getOUURI();
875 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
876
877 if ( nURLPos != ( aURL.getLength() - 1 ) )
878 aURL += rtl::OUString::createFromAscii( "/" );
879
880 sal_Int32 nLen = aURL.getLength();
881
882 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
883 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
884
885 while ( it != end ) {
886 ::ucbhelper::ContentImplHelperRef xChild = (*it);
887 rtl::OUString aChildURL
888 = xChild->getIdentifier()->getContentIdentifier();
889
890 // Is aURL a prefix of aChildURL?
891 if ( ( aChildURL.getLength() > nLen ) &&
892 ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) {
893 sal_Int32 nPos = nLen;
894 nPos = aChildURL.indexOf( '/', nPos );
895
896 if ( ( nPos == -1 ) ||
897 ( nPos == ( aChildURL.getLength() - 1 ) ) ) {
898 // No further slashes / only a final slash. It's a child!
899 rChildren.push_back( ::gvfs::Content::ContentRef
900 (static_cast< ::gvfs::Content * >(xChild.get() ) ) );
901 }
902 }
903 ++it;
904 }
905 }
906
insert(const uno::Reference<io::XInputStream> & xInputStream,sal_Bool bReplaceExisting,const uno::Reference<ucb::XCommandEnvironment> & xEnv)907 void Content::insert(
908 const uno::Reference< io::XInputStream > &xInputStream,
909 sal_Bool bReplaceExisting,
910 const uno::Reference< ucb::XCommandEnvironment > &xEnv )
911 {
912 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
913
914 #ifdef DEBUG
915 g_warning( "Insert '%s' (%d) (0x%x:%d)", getURI(), bReplaceExisting,
916 m_info.valid_fields, m_info.type );
917 #endif
918
919 GnomeVFSResult result = getInfo( xEnv );
920 // a racy design indeed.
921 if( !bReplaceExisting && !m_bTransient &&
922 result != GNOME_VFS_ERROR_NOT_FOUND) {
923 #ifdef DEBUG
924 g_warning ("Nasty error inserting to '%s' ('%s')",
925 getURI(), gnome_vfs_result_to_string( result ));
926 #endif
927 cancelCommandExecution( GNOME_VFS_ERROR_FILE_EXISTS, xEnv, sal_True );
928 }
929
930 if ( m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE &&
931 m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY ) {
932 ::rtl::OString aURI = getOURI();
933 int perm;
934
935 perm = ( GNOME_VFS_PERM_USER_ALL |
936 GNOME_VFS_PERM_GROUP_READ |
937 GNOME_VFS_PERM_OTHER_READ );
938
939 #ifdef DEBUG
940 g_warning ("Make directory");
941 #endif
942 result = gnome_vfs_make_directory( aURI.getStr(), perm );
943
944 if( result != GNOME_VFS_OK )
945 cancelCommandExecution( result, xEnv, sal_True );
946
947 return;
948 }
949
950 if ( !xInputStream.is() ) {
951 // FIXME: slightly unclear whether to accept this and create an empty file
952 ucbhelper::cancelCommandExecution
953 ( uno::makeAny
954 ( ucb::MissingInputStreamException
955 ( rtl::OUString(),
956 static_cast< cppu::OWeakObject * >( this ) ) ),
957 xEnv );
958 }
959
960 GnomeVFSHandle *handle = NULL;
961 ::rtl::OString aURI = getOURI();
962
963 result = GNOME_VFS_OK;
964 if ( bReplaceExisting ) {
965 Authentication aAuth( xEnv );
966 result = gnome_vfs_open( &handle, aURI.getStr(),
967 GNOME_VFS_OPEN_WRITE );
968 }
969
970 if ( result != GNOME_VFS_OK ) {
971 int perm;
972 Authentication aAuth( xEnv );
973
974 perm = ( ( GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ ) |
975 ( GNOME_VFS_PERM_GROUP_WRITE | GNOME_VFS_PERM_GROUP_READ ) );
976
977 result = gnome_vfs_create
978 ( &handle, aURI.getStr(), GNOME_VFS_OPEN_WRITE, TRUE, perm );
979 }
980
981 if( result != GNOME_VFS_OK )
982 cancelCommandExecution( result, xEnv, sal_True );
983
984 if ( !xInputStream.is() ) {
985 result = gnome_vfs_close( handle );
986 if (result != GNOME_VFS_OK)
987 cancelCommandExecution( result, xEnv, sal_True );
988
989 } else { // copy it over
990 uno::Reference < io::XOutputStream > xOutput =
991 new gvfs::Stream( handle, &m_info );
992
993 copyData( xInputStream, xOutput );
994 }
995
996 if (m_bTransient) {
997 m_bTransient = sal_False;
998 aGuard.clear();
999 inserted();
1000 }
1001 }
1002
transfer(const ucb::TransferInfo &,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1003 void Content::transfer(const ucb::TransferInfo & /*rArgs*/,
1004 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1005 {
1006 // FIXME: see gnome-vfs-xfer.h - but we need to be able to easily
1007 // detect which are gnome-vfs owned URI types ...
1008 ucbhelper::cancelCommandExecution
1009 ( uno::makeAny
1010 ( ucb::InteractiveBadTransferURLException
1011 ( rtl::OUString::createFromAscii( "Unsupported URL scheme!" ),
1012 static_cast< cppu::OWeakObject * >( this ) ) ),
1013 xEnv );
1014 }
1015
destroy(sal_Bool bDeletePhysical)1016 void Content::destroy( sal_Bool bDeletePhysical )
1017 {
1018 // @@@ take care about bDeletePhysical -> trashcan support
1019 rtl::OUString aURL = getOUURI();
1020
1021 uno::Reference< ucb::XContent > xThis = this;
1022
1023 deleted();
1024
1025 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1026
1027 // Process instantiated children...
1028 ::gvfs::Content::ContentRefList aChildren;
1029 queryChildren( aChildren );
1030
1031 ContentRefList::const_iterator it = aChildren.begin();
1032 ContentRefList::const_iterator end = aChildren.end();
1033
1034 while ( it != end ) {
1035 (*it)->destroy( bDeletePhysical );
1036 ++it;
1037 }
1038 }
1039
1040 // Used by the 'setPropertyValues' method for
1041 // propagating the renaming of a Content.
exchangeIdentity(const uno::Reference<ucb::XContentIdentifier> & xNewId)1042 sal_Bool Content::exchangeIdentity(
1043 const uno::Reference< ucb::XContentIdentifier >& xNewId )
1044 {
1045 if ( !xNewId.is() )
1046 return sal_False;
1047
1048 uno::Reference< ucb::XContent > xThis = this;
1049
1050 #ifdef DEBUG
1051 g_warning( "exchangeIdentity from '%s' to '%s'",
1052 getURI(), OUStringToGnome( xNewId->getContentIdentifier() ) );
1053 #endif
1054
1055 if ( m_bTransient ) {
1056 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1057 /* FIXME: can we not screw up an identically named
1058 * Content pointing to ourself here ? */
1059 m_xIdentifier = xNewId;
1060 return sal_False;
1061 }
1062
1063 rtl::OUString aOldURL = getOUURI();
1064
1065 // Exchange own identitity.
1066 if ( exchange( xNewId ) ) {
1067
1068 // Process instantiated children...
1069 ContentRefList aChildren;
1070 queryChildren( aChildren );
1071
1072 ContentRefList::const_iterator it = aChildren.begin();
1073 ContentRefList::const_iterator end = aChildren.end();
1074
1075 while ( it != end ) {
1076 ContentRef xChild = (*it);
1077
1078 // Create new content identifier for the child...
1079 uno::Reference< ucb::XContentIdentifier >
1080 xOldChildId = xChild->getIdentifier();
1081 rtl::OUString aOldChildURL
1082 = xOldChildId->getContentIdentifier();
1083 rtl::OUString aNewChildURL
1084 = aOldChildURL.replaceAt(
1085 0,
1086 aOldURL.getLength(),
1087 xNewId->getContentIdentifier() );
1088 uno::Reference< ucb::XContentIdentifier >
1089 xNewChildId
1090 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewChildURL );
1091
1092 if ( !xChild->exchangeIdentity( xNewChildId ) )
1093 return sal_False;
1094
1095 ++it;
1096 }
1097 return sal_True;
1098 }
1099
1100 return sal_False;
1101 }
1102
1103 GnomeVFSResult
getInfo(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1104 Content::getInfo( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1105 {
1106 GnomeVFSResult result;
1107 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1108
1109 if (m_bTransient)
1110 result = GNOME_VFS_OK;
1111
1112 else if ( !m_info.valid_fields ) {
1113 ::rtl::OString aURI = getOURI();
1114 Authentication aAuth( xEnv );
1115 result = gnome_vfs_get_file_info
1116 ( aURI.getStr(), &m_info, GNOME_VFS_FILE_INFO_DEFAULT );
1117 if (result != GNOME_VFS_OK)
1118 gnome_vfs_file_info_clear( &m_info );
1119 } else
1120 result = GNOME_VFS_OK;
1121 #ifdef DEBUG
1122 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)",
1123 getURI(), gnome_vfs_result_to_string( result ),
1124 result, m_info.valid_fields );
1125 #endif
1126 return result;
1127 }
1128
1129 sal_Bool
isFolder(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1130 Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1131 {
1132 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1133 getInfo( xEnv );
1134 return (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE &&
1135 m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY);
1136 }
1137
mapVFSException(const GnomeVFSResult result,sal_Bool bWrite)1138 uno::Any Content::mapVFSException( const GnomeVFSResult result, sal_Bool bWrite )
1139 {
1140 uno::Any aException;
1141 const char *gvfs_message;
1142 rtl::OUString message;
1143 uno::Sequence< uno::Any > aArgs( 1 );
1144
1145 #ifdef DEBUG
1146 g_warning ("Map VFS exception '%s' (%d)",
1147 gnome_vfs_result_to_string( result ), result );
1148 #endif
1149
1150 if ((gvfs_message = gnome_vfs_result_to_string (result)))
1151 message = GnomeToOUString( gvfs_message );
1152
1153 switch (result) {
1154 case GNOME_VFS_OK:
1155 g_warning("VFS_OK mapped to exception.");
1156 break;
1157 case GNOME_VFS_ERROR_EOF:
1158 g_warning ("VFS_EOF not handled somewhere.");
1159 break;
1160 case GNOME_VFS_ERROR_NOT_FOUND:
1161 aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
1162 aException <<=
1163 ucb::InteractiveAugmentedIOException
1164 ( rtl::OUString::createFromAscii( "Not found!" ),
1165 static_cast< cppu::OWeakObject * >( this ),
1166 task::InteractionClassification_ERROR,
1167 ucb::IOErrorCode_NOT_EXISTING,
1168 aArgs );
1169 break;
1170 case GNOME_VFS_ERROR_BAD_PARAMETERS:
1171 aException <<=
1172 lang::IllegalArgumentException
1173 ( rtl::OUString(),
1174 static_cast< cppu::OWeakObject * >( this ),
1175 -1 );
1176 break;
1177 case GNOME_VFS_ERROR_GENERIC:
1178 case GNOME_VFS_ERROR_INTERNAL:
1179 case GNOME_VFS_ERROR_NOT_SUPPORTED:
1180 #ifdef DEBUG
1181 g_warning ("Internal - un-mapped error");
1182 #endif
1183 aException <<= io::IOException();
1184 break;
1185 case GNOME_VFS_ERROR_IO:
1186 if ( bWrite )
1187 aException <<=
1188 ucb::InteractiveNetworkWriteException
1189 ( rtl::OUString(),
1190 static_cast< cppu::OWeakObject * >( this ),
1191 task::InteractionClassification_ERROR,
1192 message );
1193 else
1194 aException <<=
1195 ucb::InteractiveNetworkReadException
1196 ( rtl::OUString(),
1197 static_cast< cppu::OWeakObject * >( this ),
1198 task::InteractionClassification_ERROR,
1199 message );
1200 break;
1201 case GNOME_VFS_ERROR_HOST_NOT_FOUND:
1202 case GNOME_VFS_ERROR_INVALID_HOST_NAME:
1203 aException <<=
1204 ucb::InteractiveNetworkResolveNameException
1205 ( rtl::OUString(),
1206 static_cast< cppu::OWeakObject * >( this ),
1207 task::InteractionClassification_ERROR,
1208 message );
1209 break;
1210 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE:
1211 case GNOME_VFS_ERROR_SERVICE_OBSOLETE:
1212 case GNOME_VFS_ERROR_PROTOCOL_ERROR:
1213 case GNOME_VFS_ERROR_NO_MASTER_BROWSER:
1214 aException <<=
1215 ucb::InteractiveNetworkConnectException
1216 ( rtl::OUString(),
1217 static_cast< cppu::OWeakObject * >( this ),
1218 task::InteractionClassification_ERROR,
1219 message );
1220 break;
1221
1222 case GNOME_VFS_ERROR_FILE_EXISTS:
1223 aException <<= ucb::NameClashException
1224 ( rtl::OUString(),
1225 static_cast< cppu::OWeakObject * >( this ),
1226 task::InteractionClassification_ERROR,
1227 message );
1228 break;
1229
1230 case GNOME_VFS_ERROR_INVALID_OPEN_MODE:
1231 aException <<= ucb::UnsupportedOpenModeException();
1232 break;
1233
1234 case GNOME_VFS_ERROR_CORRUPTED_DATA:
1235 case GNOME_VFS_ERROR_WRONG_FORMAT:
1236 case GNOME_VFS_ERROR_BAD_FILE:
1237 case GNOME_VFS_ERROR_TOO_BIG:
1238 case GNOME_VFS_ERROR_NO_SPACE:
1239 case GNOME_VFS_ERROR_READ_ONLY:
1240 case GNOME_VFS_ERROR_INVALID_URI:
1241 case GNOME_VFS_ERROR_NOT_OPEN:
1242 case GNOME_VFS_ERROR_ACCESS_DENIED:
1243 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES:
1244 case GNOME_VFS_ERROR_NOT_A_DIRECTORY:
1245 case GNOME_VFS_ERROR_IN_PROGRESS:
1246 case GNOME_VFS_ERROR_INTERRUPTED:
1247 case GNOME_VFS_ERROR_LOOP:
1248 case GNOME_VFS_ERROR_NOT_PERMITTED:
1249 case GNOME_VFS_ERROR_IS_DIRECTORY:
1250 case GNOME_VFS_ERROR_NO_MEMORY:
1251 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS:
1252 case GNOME_VFS_ERROR_LOGIN_FAILED:
1253 case GNOME_VFS_ERROR_CANCELLED:
1254 case GNOME_VFS_ERROR_DIRECTORY_BUSY:
1255 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY:
1256 case GNOME_VFS_ERROR_TOO_MANY_LINKS:
1257 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM:
1258 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM:
1259 case GNOME_VFS_ERROR_NAME_TOO_LONG:
1260 #ifdef DEBUG
1261 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)",
1262 gnome_vfs_result_to_string( result ), result );
1263 #endif
1264 default:
1265 aException <<= ucb::InteractiveNetworkGeneralException
1266 ( rtl::OUString(),
1267 static_cast< cppu::OWeakObject * >( this ),
1268 task::InteractionClassification_ERROR );
1269 break;
1270 }
1271
1272 return aException;
1273 }
1274
cancelCommandExecution(GnomeVFSResult result,const uno::Reference<ucb::XCommandEnvironment> & xEnv,sal_Bool bWrite)1275 void Content::cancelCommandExecution(
1276 GnomeVFSResult result,
1277 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
1278 sal_Bool bWrite /* = sal_False */ )
1279 {
1280 ucbhelper::cancelCommandExecution( mapVFSException( result, bWrite ), xEnv );
1281 // Unreachable
1282 }
1283
getProperties(const uno::Reference<ucb::XCommandEnvironment> &)1284 uno::Sequence< beans::Property > Content::getProperties(
1285 const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
1286 {
1287 static const beans::Property aGenericProperties[] = {
1288 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ),
1289 -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1290 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1291 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
1292 -1, getCppuBooleanType(),
1293 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1294 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
1295 -1, getCppuBooleanType(),
1296 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1297 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1298 -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1299 beans::PropertyAttribute::BOUND ),
1300 // Optional ...
1301 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ),
1302 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1303 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1304 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ),
1305 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1306 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1307 // FIXME: Too expensive for now (?)
1308 // beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
1309 // -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1310 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1311 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ),
1312 -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ),
1313 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1314 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ),
1315 -1, getCppuBooleanType(),
1316 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1317 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsVolume" ) ),
1318 -1, getCppuBooleanType(),
1319 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1320 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsCompactDisk" ) ),
1321 -1, getCppuBooleanType(),
1322 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1323 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ),
1324 -1, getCppuBooleanType(),
1325 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1326 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
1327 -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1328 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY )
1329 };
1330
1331 const int nProps = sizeof (aGenericProperties) / sizeof (aGenericProperties[0]);
1332
1333 return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
1334
1335 }
1336
getCommands(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1337 uno::Sequence< ucb::CommandInfo > Content::getCommands(
1338 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1339 {
1340 static ucb::CommandInfo aCommandInfoTable[] = {
1341 // Required commands
1342 ucb::CommandInfo
1343 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ),
1344 -1, getCppuVoidType() ),
1345 ucb::CommandInfo
1346 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ),
1347 -1, getCppuVoidType() ),
1348 ucb::CommandInfo
1349 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ),
1350 -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
1351 ucb::CommandInfo
1352 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
1353 -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
1354
1355 // Optional standard commands
1356 ucb::CommandInfo
1357 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ),
1358 -1, getCppuBooleanType() ),
1359 ucb::CommandInfo
1360 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ),
1361 -1, getCppuType( static_cast<ucb::InsertCommandArgument * >( 0 ) ) ),
1362 ucb::CommandInfo
1363 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ),
1364 -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
1365
1366 // Folder Only, omitted if not a folder
1367 ucb::CommandInfo
1368 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ),
1369 -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1370 ucb::CommandInfo
1371 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "createNewContent" ) ),
1372 -1, getCppuType( static_cast<ucb::ContentInfo * >( 0 ) ) )
1373 };
1374
1375 const int nProps
1376 = sizeof( aCommandInfoTable ) / sizeof( aCommandInfoTable[ 0 ] );
1377 return uno::Sequence< ucb::CommandInfo >(
1378 aCommandInfoTable, isFolder( xEnv ) ? nProps : nProps - 2 );
1379 }
1380
1381 rtl::OUString
getOUURI()1382 Content::getOUURI ()
1383 {
1384 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1385 return m_xIdentifier->getContentIdentifier();
1386 }
1387
1388 rtl::OString
getOURI()1389 Content::getOURI ()
1390 {
1391 return rtl::OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8 );
1392 }
1393
1394 char *
getURI()1395 Content::getURI ()
1396 {
1397 return OUStringToGnome( getOUURI() );
1398 }
1399
1400 void
copyData(uno::Reference<io::XInputStream> xIn,uno::Reference<io::XOutputStream> xOut)1401 Content::copyData( uno::Reference< io::XInputStream > xIn,
1402 uno::Reference< io::XOutputStream > xOut )
1403 {
1404 uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
1405
1406 g_return_if_fail( xIn.is() && xOut.is() );
1407
1408 while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
1409 xOut->writeBytes( theData );
1410
1411 xOut->closeOutput();
1412 }
1413
1414 // Inherits an authentication context
1415 uno::Reference< io::XInputStream >
createTempStream(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1416 Content::createTempStream(
1417 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1418 {
1419 GnomeVFSResult result;
1420 GnomeVFSHandle *handle = NULL;
1421 ::rtl::OString aURI = getOURI();
1422
1423 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1424 // Something badly wrong happened - can't seek => stream to a temporary file
1425 const rtl::OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1426 uno::Reference < io::XOutputStream > xTempOut =
1427 uno::Reference < io::XOutputStream >
1428 ( m_xSMgr->createInstance( sServiceName ), uno::UNO_QUERY );
1429
1430 if ( !xTempOut.is() )
1431 cancelCommandExecution( GNOME_VFS_ERROR_IO, xEnv );
1432
1433 result = gnome_vfs_open( &handle, aURI.getStr(), GNOME_VFS_OPEN_READ );
1434 if (result != GNOME_VFS_OK)
1435 cancelCommandExecution( result, xEnv );
1436
1437 uno::Reference < io::XInputStream > pStream = new ::gvfs::Stream( handle, &m_info );
1438 copyData( pStream, xTempOut );
1439
1440 return uno::Reference < io::XInputStream > ( xTempOut, uno::UNO_QUERY );
1441 }
1442
1443 uno::Reference< io::XInputStream >
createInputStream(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1444 Content::createInputStream(
1445 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1446 {
1447 GnomeVFSHandle *handle = NULL;
1448 GnomeVFSResult result;
1449 uno::Reference<io::XInputStream > xIn;
1450
1451 Authentication aAuth( xEnv );
1452 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1453
1454 getInfo( xEnv );
1455 ::rtl::OString aURI = getOURI();
1456
1457 if ( !(m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) )
1458 return createTempStream( xEnv );
1459
1460 result = gnome_vfs_open( &handle, aURI.getStr(),
1461 (GnomeVFSOpenMode) (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_RANDOM ) );
1462
1463 if (result == GNOME_VFS_ERROR_INVALID_OPEN_MODE ||
1464 result == GNOME_VFS_ERROR_NOT_SUPPORTED)
1465 return createTempStream( xEnv );
1466
1467 if (result != GNOME_VFS_OK)
1468 cancelCommandExecution( result, xEnv );
1469
1470 // Try a seek just to make sure it's Random access: some lie.
1471 result = gnome_vfs_seek( handle, GNOME_VFS_SEEK_START, 0);
1472 if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) {
1473 gnome_vfs_close( handle );
1474 return createTempStream( xEnv );
1475 }
1476
1477 if (result != GNOME_VFS_OK)
1478 cancelCommandExecution( result, xEnv );
1479
1480 if (handle != NULL)
1481 xIn = new ::gvfs::Stream( handle, &m_info );
1482
1483 return xIn;
1484 }
1485
1486 sal_Bool
feedSink(uno::Reference<uno::XInterface> aSink,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1487 Content::feedSink( uno::Reference< uno::XInterface > aSink,
1488 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1489 {
1490 if ( !aSink.is() )
1491 return sal_False;
1492
1493 uno::Reference< io::XOutputStream > xOut
1494 = uno::Reference< io::XOutputStream >(aSink, uno::UNO_QUERY );
1495 uno::Reference< io::XActiveDataSink > xDataSink
1496 = uno::Reference< io::XActiveDataSink >(aSink, uno::UNO_QUERY );
1497
1498 if ( !xOut.is() && !xDataSink.is() )
1499 return sal_False;
1500
1501 uno::Reference< io::XInputStream > xIn = createInputStream( xEnv );
1502 if ( !xIn.is() )
1503 return sal_False;
1504
1505 if ( xOut.is() )
1506 copyData( xIn, xOut );
1507
1508 if ( xDataSink.is() )
1509 xDataSink->setInputStream( xIn );
1510
1511 return sal_True;
1512 }
1513
1514 extern "C" {
1515
1516 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
1517 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)"
1518 #endif
1519
1520 static void
vfs_authentication_callback(gconstpointer in_void,gsize in_size,gpointer out_void,gsize out_size,gpointer callback_data)1521 vfs_authentication_callback (gconstpointer in_void,
1522 gsize in_size,
1523 gpointer out_void,
1524 gsize out_size,
1525 gpointer callback_data)
1526 {
1527 task::XInteractionHandler *xIH;
1528
1529 #ifdef DEBUG
1530 g_warning ("Full authentication callback (%p) ...", callback_data);
1531 #endif
1532
1533 if( !( xIH = (task::XInteractionHandler *) callback_data ) )
1534 return;
1535
1536 const GnomeVFSModuleCallbackFullAuthenticationIn *in =
1537 (const GnomeVFSModuleCallbackFullAuthenticationIn *) in_void;
1538 GnomeVFSModuleCallbackFullAuthenticationOut *out =
1539 (GnomeVFSModuleCallbackFullAuthenticationOut *) out_void;
1540
1541 g_return_if_fail (in != NULL && out != NULL);
1542 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn) == in_size &&
1543 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut) == out_size);
1544
1545 #ifdef DEBUG
1546 # define NNIL(x) (x?x:"<Null>")
1547 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' "
1548 "port %d auth_t '%s' user '%s' domain '%s' "
1549 "def user '%s', def domain '%s'",
1550 (int) in->flags, NNIL(in->uri), NNIL(in->protocol),
1551 NNIL(in->server), NNIL(in->object),
1552 (int) in->port, NNIL(in->authtype), NNIL(in->username), NNIL(in->domain),
1553 NNIL(in->default_user), NNIL(in->default_domain));
1554 # undef NNIL
1555 #endif
1556
1557 ucbhelper::SimpleAuthenticationRequest::EntityType
1558 eDomain, eUserName, ePassword;
1559 ::rtl::OUString aHostName, aDomain, aUserName, aPassword;
1560
1561 aHostName = GnomeToOUString( in->server );
1562
1563 if (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN)
1564 {
1565 aDomain = GnomeToOUString( in->domain );
1566 eDomain = ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY;
1567 if (!aDomain.getLength())
1568 aDomain = GnomeToOUString( in->default_domain );
1569 }
1570 else // no underlying capability to display realm otherwise
1571 eDomain = ucbhelper::SimpleAuthenticationRequest::ENTITY_NA;
1572
1573 aUserName = GnomeToOUString( in->username );
1574 if (!aUserName.getLength())
1575 aUserName = GnomeToOUString( in->default_user );
1576 eUserName = (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) ?
1577 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY :
1578 (aUserName.getLength() ?
1579 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED :
1580 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA);
1581
1582 // No suggested password.
1583 ePassword = (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD) ?
1584 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY :
1585 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED;
1586
1587 // Really, really bad things happen if we don't provide
1588 // the same user/password as was entered last time if
1589 // we failed to authenticate - infinite looping / flickering
1590 // madness etc. [ nice infrastructure ! ]
1591 static rtl::OUString aLastUserName, aLastPassword;
1592 if (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED)
1593 {
1594 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
1595 aUserName = aLastUserName;
1596 aPassword = aLastPassword;
1597 }
1598
1599 rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
1600 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in->uri),
1601 aHostName, eDomain, aDomain,
1602 eUserName, aUserName,
1603 ePassword, aPassword);
1604
1605 xIH->handle( xRequest.get() );
1606
1607 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
1608 = xRequest->getSelection();
1609
1610 if ( xSelection.is() ) {
1611 // Handler handled the request.
1612 uno::Reference< task::XInteractionAbort > xAbort(xSelection.get(), uno::UNO_QUERY );
1613 if ( !xAbort.is() ) {
1614 const rtl::Reference<
1615 ucbhelper::InteractionSupplyAuthentication > & xSupp
1616 = xRequest->getAuthenticationSupplier();
1617
1618 aUserName = xSupp->getUserName();
1619 aDomain = xSupp->getRealm();
1620 aPassword = xSupp->getPassword();
1621
1622 {
1623 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
1624 aLastUserName = aUserName;
1625 aLastPassword = aPassword;
1626 }
1627
1628 out->username = OUStringToGnome( aUserName );
1629 out->domain = OUStringToGnome( aDomain );
1630 out->password = OUStringToGnome( aPassword );
1631 out->save_password = xSupp->getRememberPasswordMode();
1632
1633 #ifdef DEBUG
1634 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password",
1635 out->username, out->domain, out->password,
1636 out->save_password ? "save" : "don't save");
1637 #endif
1638 }
1639 else
1640 out->abort_auth = TRUE;
1641 }
1642 else
1643 out->abort_auth = TRUE;
1644 }
1645
1646 static void
vfs_authentication_old_callback(gconstpointer in_void,gsize in_size,gpointer out_void,gsize out_size,gpointer callback_data)1647 vfs_authentication_old_callback (gconstpointer in_void,
1648 gsize in_size,
1649 gpointer out_void,
1650 gsize out_size,
1651 gpointer callback_data)
1652 {
1653 #ifdef DEBUG
1654 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data);
1655 #endif
1656 const GnomeVFSModuleCallbackAuthenticationIn *in =
1657 (const GnomeVFSModuleCallbackAuthenticationIn *) in_void;
1658 GnomeVFSModuleCallbackAuthenticationOut *out =
1659 (GnomeVFSModuleCallbackAuthenticationOut *) out_void;
1660
1661 g_return_if_fail (in != NULL && out != NULL);
1662 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn) == in_size &&
1663 sizeof (GnomeVFSModuleCallbackAuthenticationOut) == out_size);
1664
1665 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in = {
1666 (GnomeVFSModuleCallbackFullAuthenticationFlags)
1667 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD |
1668 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME |
1669 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN),
1670 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1671 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out = { 0, 0, 0, 0, 0, 0, 0, 0 };
1672
1673 // Map the old style input auth. data to the new style structure.
1674 if (in->previous_attempt_failed)
1675 mapped_in.flags = (GnomeVFSModuleCallbackFullAuthenticationFlags)
1676 (mapped_in.flags |
1677 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED);
1678
1679 GnomeVFSURI *pURI = NULL;
1680 // Urk - parse all this from the URL ...
1681 mapped_in.uri = in->uri;
1682 if (in->uri)
1683 {
1684 pURI = gnome_vfs_uri_new( in->uri );
1685 mapped_in.protocol = (char *) gnome_vfs_uri_get_scheme (pURI);
1686 mapped_in.server = (char *) gnome_vfs_uri_get_host_name (pURI);
1687 mapped_in.port = gnome_vfs_uri_get_host_port (pURI);
1688 mapped_in.username = (char *) gnome_vfs_uri_get_user_name (pURI);
1689 }
1690 mapped_in.domain = in->realm;
1691 mapped_in.default_user = mapped_in.username;
1692 mapped_in.default_domain = mapped_in.domain;
1693
1694 vfs_authentication_callback ((gconstpointer) &mapped_in,
1695 sizeof (mapped_in),
1696 (gpointer) &mapped_out,
1697 sizeof (mapped_out),
1698 callback_data);
1699
1700 if (pURI)
1701 gnome_vfs_uri_unref (pURI);
1702
1703 // Map the new style auth. out data to the old style out structure.
1704 out->username = mapped_out.username;
1705 out->password = mapped_out.password;
1706 g_free (mapped_out.domain);
1707 g_free (mapped_out.keyring);
1708 }
1709
1710
1711 static void
auth_destroy(gpointer data)1712 auth_destroy (gpointer data)
1713 {
1714 task::XInteractionHandler *xIH;
1715 if( ( xIH = ( task::XInteractionHandler * )data ) )
1716 xIH->release();
1717 }
1718
1719 // This sucks, but gnome-vfs doesn't much like
1720 // repeated set / unsets - so we have to compensate.
1721 GPrivate *auth_queue = NULL;
1722
auth_queue_destroy(gpointer data)1723 void auth_queue_destroy( gpointer data )
1724 {
1725 GList *l;
1726 GQueue *vq = (GQueue *) data;
1727
1728 for (l = vq->head; l; l = l->next)
1729 auth_destroy (l->data);
1730 g_queue_free (vq);
1731 }
1732 }
1733
1734 static void
refresh_auth(GQueue * vq)1735 refresh_auth( GQueue *vq )
1736 {
1737 GList *l;
1738
1739 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION );
1740 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION );
1741
1742 for (l = vq->head; l; l = l->next) {
1743 if (l->data) {
1744 gnome_vfs_module_callback_push
1745 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION,
1746 vfs_authentication_old_callback, l->data, NULL );
1747 gnome_vfs_module_callback_push
1748 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION,
1749 vfs_authentication_callback, l->data, NULL );
1750 break;
1751 }
1752 }
1753 }
1754
Authentication(const uno::Reference<ucb::XCommandEnvironment> & xEnv)1755 gvfs::Authentication::Authentication(
1756 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1757 {
1758 GQueue *vq;
1759 uno::Reference< task::XInteractionHandler > xIH;
1760
1761 if ( xEnv.is() )
1762 xIH = xEnv->getInteractionHandler();
1763
1764 if ( xIH.is() )
1765 xIH->acquire();
1766
1767 if( !(vq = (GQueue *)g_private_get( auth_queue ) ) ) {
1768 vq = g_queue_new();
1769 g_private_set( auth_queue, vq );
1770 }
1771
1772 g_queue_push_head( vq, (gpointer) xIH.get() );
1773 refresh_auth( vq );
1774 }
1775
~Authentication()1776 gvfs::Authentication::~Authentication()
1777 {
1778 GQueue *vq;
1779 gpointer data;
1780
1781 vq = (GQueue *)g_private_get( auth_queue );
1782
1783 data = g_queue_pop_head( vq );
1784 auth_destroy (data);
1785
1786 refresh_auth( vq );
1787 }
1788