1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <sys/types.h>
24 #include <sal/macros.h>
26 #include <osl/diagnose.h>
28 #include "osl/doublecheckedlocking.h"
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
33 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
34 #include <com/sun/star/io/XActiveDataSink.hpp>
35 #include <com/sun/star/io/XOutputStream.hpp>
36 #include <com/sun/star/io/TempFile.hpp>
37 #include <com/sun/star/lang/IllegalAccessException.hpp>
38 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
39 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
40 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
41 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
42 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
43 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
44 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
45 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
46 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
47 #include <com/sun/star/ucb/NameClash.hpp>
48 #include <com/sun/star/ucb/NameClashException.hpp>
49 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
50 #include <com/sun/star/ucb/OpenMode.hpp>
51 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
52 #include <com/sun/star/ucb/TransferInfo.hpp>
53 #include <com/sun/star/ucb/XCommandInfo.hpp>
54 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
55 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
56 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
57 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
58 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
59 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
60 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
61 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
62 #include <com/sun/star/ucb/NameClashException.hpp>
63 #include <comphelper/processfactory.hxx>
64 #include <ucbhelper/contentidentifier.hxx>
65 #include <ucbhelper/propertyvalueset.hxx>
66 #include <ucbhelper/interactionrequest.hxx>
67 #include <ucbhelper/cancelcommandexecution.hxx>
68 #include <ucbhelper/simpleauthenticationrequest.hxx>
70 const int TRANSFER_BUFFER_SIZE
= 65536;
73 * NB. Name escaping is done only for URIs
74 * the 'Title' property is unescaped on set/get
76 #include <libgnomevfs/gnome-vfs-utils.h>
77 #include <libgnomevfs/gnome-vfs-result.h>
78 #include <libgnomevfs/gnome-vfs-standard-callbacks.h>
79 extern "C" { // missing in the header: doh.
80 # include <libgnomevfs/gnome-vfs-module-callback.h>
83 #include "gvfs_content.hxx"
84 #include "gvfs_provider.hxx"
85 #include "gvfs_directory.hxx"
86 #include "gvfs_stream.hxx"
89 using namespace com::sun::star
;
91 #define CLEAR_INFO(info) memset((info), 0, sizeof ((info)[0]))
95 OUStringToGnome( const rtl::OUString
&str
)
97 rtl::OString aTempStr
= rtl::OUStringToOString( str
, RTL_TEXTENCODING_UTF8
);
98 return g_strdup( aTempStr
.getStr() );
102 GnomeToOUString( const char *utf8_str
)
105 return rtl::OUString();
107 return rtl::OUString( utf8_str
, strlen( utf8_str
), RTL_TEXTENCODING_UTF8
);
112 const uno::Reference
< uno::XComponentContext
>& rxContext
,
113 ContentProvider
* pProvider
,
114 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
115 throw ( ucb::ContentCreationException
)
116 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
117 m_pProvider( pProvider
),
118 m_bTransient( sal_False
)
120 CLEAR_INFO (&m_info
);
121 #if OSL_DEBUG_LEVEL > 1
122 g_warning ("New Content ('%s')", getURI());
127 const uno::Reference
< uno::XComponentContext
>& rxContext
,
128 ContentProvider
* pProvider
,
129 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
131 throw ( ucb::ContentCreationException
)
132 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
133 m_pProvider( pProvider
),
134 m_bTransient( sal_True
)
136 CLEAR_INFO (&m_info
);
138 #if OSL_DEBUG_LEVEL > 1
139 g_warning ("New Transient content ('%s') (%d)", getURI(), IsFolder
);
141 // m_info.name = FIXME: set name ?
142 m_info
.valid_fields
= GNOME_VFS_FILE_INFO_FIELDS_TYPE
;
143 m_info
.type
= IsFolder
? GNOME_VFS_FILE_TYPE_DIRECTORY
:
144 GNOME_VFS_FILE_TYPE_REGULAR
;
150 gnome_vfs_file_info_clear( &m_info
);
154 // XInterface methods.
157 void SAL_CALL
Content::acquire()
160 ContentImplHelper::acquire();
162 void SAL_CALL
Content::release()
165 ContentImplHelper::release();
167 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
168 throw ( uno::RuntimeException
)
170 // Note: isFolder may require network activities! So call it only
171 // if it is really necessary!!!
172 uno::Any aRet
= cppu::queryInterface( rType
,
173 static_cast< ucb::XContentCreator
* >( this ) );
174 if ( aRet
.hasValue() )
175 return isFolder( uno::Reference
< ucb::XCommandEnvironment
>() )
178 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
182 // XTypeProvider methods.
185 XTYPEPROVIDER_COMMON_IMPL( Content
);
187 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
188 throw( uno::RuntimeException
)
190 static cppu::OTypeCollection
*pFolderCollection
= NULL
;
191 static cppu::OTypeCollection
*pFileCollection
= NULL
;
193 if (!pFolderCollection
) {
194 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
196 if (!pFolderCollection
) {
197 static cppu::OTypeCollection aFolderCollection
198 (CPPU_TYPE_REF( lang::XTypeProvider
),
199 CPPU_TYPE_REF( lang::XServiceInfo
),
200 CPPU_TYPE_REF( lang::XComponent
),
201 CPPU_TYPE_REF( ucb::XContent
),
202 CPPU_TYPE_REF( ucb::XCommandProcessor
),
203 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
204 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
205 CPPU_TYPE_REF( beans::XPropertyContainer
),
206 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
207 CPPU_TYPE_REF( container::XChild
),
208 CPPU_TYPE_REF( ucb::XContentCreator
) ); // !!
209 static cppu::OTypeCollection aFileCollection
210 (CPPU_TYPE_REF( lang::XTypeProvider
),
211 CPPU_TYPE_REF( lang::XServiceInfo
),
212 CPPU_TYPE_REF( lang::XComponent
),
213 CPPU_TYPE_REF( ucb::XContent
),
214 CPPU_TYPE_REF( ucb::XCommandProcessor
),
215 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
216 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
217 CPPU_TYPE_REF( beans::XPropertyContainer
),
218 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
219 CPPU_TYPE_REF( container::XChild
) );
221 pFolderCollection
= &aFolderCollection
;
222 pFileCollection
= &aFileCollection
;
223 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
227 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
230 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
231 return pFolderCollection
->getTypes();
233 return pFileCollection
->getTypes();
237 // XServiceInfo methods.
240 rtl::OUString SAL_CALL
Content::getImplementationName()
241 throw( uno::RuntimeException
)
243 return rtl::OUString("com.sun.star.comp.GnomeVFSContent");
246 uno::Sequence
< rtl::OUString
> SAL_CALL
Content::getSupportedServiceNames()
247 throw( uno::RuntimeException
)
249 uno::Sequence
< rtl::OUString
> aSNS( 1 );
250 aSNS
.getArray()[ 0 ] = rtl::OUString( "com.sun.star.ucb.GnomeVFSContent" );
258 rtl::OUString SAL_CALL
Content::getContentType()
259 throw( uno::RuntimeException
)
261 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
262 return rtl::OUString( GVFS_FOLDER_TYPE
);
264 return rtl::OUString( GVFS_FILE_TYPE
);
268 // XCommandProcessor methods.
271 uno::Any
Content::getBadArgExcept()
273 return uno::makeAny( lang::IllegalArgumentException
274 ( rtl::OUString("Wrong argument type!"),
275 static_cast< cppu::OWeakObject
* >( this ),
281 uno::Any SAL_CALL
Content::execute(
282 const ucb::Command
& aCommand
,
283 sal_Int32
/*CommandId*/,
284 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
285 throw( uno::Exception
,
286 ucb::CommandAbortedException
,
287 uno::RuntimeException
)
291 #if OSL_DEBUG_LEVEL > 1
293 uno::Reference
< task::XInteractionHandler
> xIH
;
296 xIH
= xEnv
->getInteractionHandler();
297 g_warning( "Execute command: '%s' with %s interaction env",
298 OUStringToGnome( aCommand
.Name
),
299 xIH
.is() ? "" : "NO" );
303 #define COMMAND_IS(cmd,name) ( (cmd).Name == name )
305 if ( COMMAND_IS( aCommand
, "getPropertyValues" ) ) {
306 uno::Sequence
< beans::Property
> Properties
;
308 if ( !( aCommand
.Argument
>>= Properties
) )
309 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
311 aRet
<<= getPropertyValues( Properties
, xEnv
);
313 } else if ( COMMAND_IS( aCommand
, "setPropertyValues" ) ) {
314 uno::Sequence
< beans::PropertyValue
> aProperties
;
316 if ( !( aCommand
.Argument
>>= aProperties
) ||
317 !aProperties
.getLength() )
318 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
320 aRet
<<= setPropertyValues( aProperties
, xEnv
);
322 } else if ( COMMAND_IS( aCommand
, "getPropertySetInfo" ) ) {
323 aRet
<<= getPropertySetInfo( xEnv
, sal_False
);
325 } else if ( COMMAND_IS( aCommand
, "getCommandInfo" ) ) {
326 aRet
<<= getCommandInfo( xEnv
, sal_False
);
328 } else if ( COMMAND_IS( aCommand
, "open" ) ) {
329 rtl::OUString str
= m_xIdentifier
->getContentIdentifier();
333 RTL_TEXTENCODING_UTF8
);
335 ucb::OpenCommandArgument2 aOpenCommand
;
336 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
337 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
339 sal_Bool bOpenFolder
=
340 ( ( aOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
341 ( aOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
342 ( aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
) );
344 if ( bOpenFolder
&& isFolder( xEnv
) ) {
345 uno::Reference
< ucb::XDynamicResultSet
> xSet
346 = new DynamicResultSet( m_xContext
, this, aOpenCommand
, xEnv
);
349 } else if ( aOpenCommand
.Sink
.is() ) {
351 if ( ( aOpenCommand
.Mode
352 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
354 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) ) {
355 ucbhelper::cancelCommandExecution
356 ( uno::makeAny ( ucb::UnsupportedOpenModeException
358 static_cast< cppu::OWeakObject
* >( this ),
359 sal_Int16( aOpenCommand
.Mode
) ) ),
362 if ( !feedSink( aOpenCommand
.Sink
, xEnv
) ) {
363 // Note: aOpenCommand.Sink may contain an XStream
364 // implementation. Support for this type of
365 // sink is optional...
367 g_warning ("Failed to load data from '%s'", getURI());
369 ucbhelper::cancelCommandExecution
370 ( uno::makeAny (ucb::UnsupportedDataSinkException
372 static_cast< cppu::OWeakObject
* >( this ),
373 aOpenCommand
.Sink
) ),
379 g_warning ("Open falling through ...");
382 } else if ( COMMAND_IS( aCommand
, "createNewContent" ) && isFolder( xEnv
) ) {
383 ucb::ContentInfo arg
;
384 if ( !( aCommand
.Argument
>>= arg
) )
385 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
387 aRet
<<= createNewContent( arg
);
389 } else if ( COMMAND_IS( aCommand
, "insert" ) ) {
390 ucb::InsertCommandArgument arg
;
391 if ( !( aCommand
.Argument
>>= arg
) )
392 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
394 insert( arg
.Data
, arg
.ReplaceExisting
, xEnv
);
396 } else if ( COMMAND_IS( aCommand
, "delete" ) ) {
398 sal_Bool bDeletePhysical
= sal_False
;
399 aCommand
.Argument
>>= bDeletePhysical
;
401 ::rtl::OString aURI
= getOURI();
402 GnomeVFSResult result
= gnome_vfs_unlink (aURI
.getStr());
404 if (result
!= GNOME_VFS_OK
)
405 cancelCommandExecution( result
, xEnv
, sal_True
);
407 destroy( bDeletePhysical
);
409 } else if ( COMMAND_IS( aCommand
, "transfer" ) && isFolder( xEnv
) ) {
410 ucb::TransferInfo transferArgs
;
412 if ( !( aCommand
.Argument
>>= transferArgs
) )
413 ucbhelper::cancelCommandExecution( getBadArgExcept(), xEnv
);
415 transfer( transferArgs
, xEnv
);
417 } else { // Unsuported
419 g_warning( "Unsupported command: '%s'",
420 OUStringToGnome( aCommand
.Name
) );
422 ucbhelper::cancelCommandExecution
423 ( uno::makeAny( ucb::UnsupportedCommandException
425 static_cast< cppu::OWeakObject
* >( this ) ) ),
433 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
434 throw( uno::RuntimeException
)
436 // FIXME: we should use the GnomeVFSCancellation APIs here ...
440 // XContentCreator methods.
443 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
444 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
445 throw( uno::RuntimeException
)
447 if ( isFolder( xEnv
) )
449 uno::Sequence
< ucb::ContentInfo
> seq(2);
451 // Minimum set of props we really need
452 uno::Sequence
< beans::Property
> props( 1 );
453 props
[0] = beans::Property(
454 rtl::OUString("Title"),
456 getCppuType( static_cast< rtl::OUString
* >( 0 ) ),
457 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
);
460 seq
[0].Type
= rtl::OUString( GVFS_FILE_TYPE
);
461 seq
[0].Attributes
= ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
462 ucb::ContentInfoAttribute::KIND_DOCUMENT
);
463 seq
[0].Properties
= props
;
466 seq
[1].Type
= rtl::OUString( GVFS_FOLDER_TYPE
);
467 seq
[1].Attributes
= ucb::ContentInfoAttribute::KIND_FOLDER
;
468 seq
[1].Properties
= props
;
474 return uno::Sequence
< ucb::ContentInfo
>();
478 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
479 throw( uno::RuntimeException
)
481 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
484 uno::Reference
< ucb::XContent
> SAL_CALL
485 Content::createNewContent( const ucb::ContentInfo
& Info
)
486 throw( uno::RuntimeException
)
488 bool create_document
;
491 if ( Info
.Type
== GVFS_FILE_TYPE
)
492 create_document
= true;
493 else if ( Info
.Type
== GVFS_FOLDER_TYPE
)
494 create_document
= false;
497 g_warning( "Failed to create new content '%s'",
498 OUStringToGnome( Info
.Type
) );
500 return uno::Reference
< ucb::XContent
>();
503 #if OSL_DEBUG_LEVEL > 1
504 g_warning( "createNewContent (%d)", (int) create_document
);
507 rtl::OUString aURL
= getOUURI();
509 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
510 aURL
+= rtl::OUString("/");
512 name
= create_document
? "[New_Content]" : "[New_Collection]";
513 // This looks problematic to me cf. webdav
514 aURL
+= rtl::OUString::createFromAscii( name
);
516 uno::Reference
< ucb::XContentIdentifier
> xId
517 ( new ::ucbhelper::ContentIdentifier( aURL
) );
520 return new ::gvfs::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
521 } catch ( ucb::ContentCreationException
& ) {
522 return uno::Reference
< ucb::XContent
>();
526 rtl::OUString
Content::getParentURL()
528 rtl::OUString aParentURL
;
530 // <scheme>://foo -> ""
531 // <scheme>://foo/ -> ""
532 // <scheme>://foo/bar -> <scheme>://foo/
533 // <scheme>://foo/bar/ -> <scheme>://foo/
534 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
536 rtl::OUString aURL
= getOUURI();
538 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
539 if ( nPos
== ( aURL
.getLength() - 1 ) ) {
540 // Trailing slash found. Skip.
541 nPos
= aURL
.lastIndexOf( '/', nPos
);
544 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
546 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
549 aParentURL
= rtl::OUString( aURL
.copy( 0, nPos
+ 1 ) );
551 #if OSL_DEBUG_LEVEL > 1
552 g_warning ("getParentURL '%s' -> '%s'",
553 getURI(), rtl::OUStringToOString
554 ( aParentURL
, RTL_TEXTENCODING_UTF8
).getStr() );
560 static util::DateTime
561 getDateFromUnix (time_t t
)
568 if ( osl_getDateTimeFromTimeValue( &tv
, &dt
) )
569 return util::DateTime( 0, dt
.Seconds
, dt
.Minutes
, dt
.Hours
,
570 dt
.Day
, dt
.Month
, dt
.Year
);
572 return util::DateTime();
575 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
576 const uno::Sequence
< beans::Property
>& rProperties
,
577 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
580 GnomeVFSResult result
;
581 uno::Sequence
< beans::Property
> allProperties
;
583 if( ( result
= getInfo( xEnv
) ) != GNOME_VFS_OK
)
584 cancelCommandExecution( result
, xEnv
, sal_False
);
586 const beans::Property
* pProps
;
588 if( rProperties
.getLength() ) {
589 nProps
= rProperties
.getLength();
590 pProps
= rProperties
.getConstArray();
592 allProperties
= getPropertySetInfo( xEnv
)->getProperties();
593 nProps
= allProperties
.getLength();
594 pProps
= allProperties
.getConstArray();
597 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
598 = new ::ucbhelper::PropertyValueSet( m_xContext
);
600 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
601 for( sal_Int32 n
= 0; n
< nProps
; ++n
) {
602 const beans::Property
& rProp
= pProps
[ n
];
604 if ( rProp
.Name
== "Title" ) {
605 if (m_info
.name
&& m_info
.name
[0] == '/')
606 g_warning ("Odd NFS title on item '%s' == '%s'",
607 getURI(), m_info
.name
);
608 xRow
->appendString( rProp
, GnomeToOUString( m_info
.name
) );
611 else if ( rProp
.Name
== "ContentType" )
612 xRow
->appendString( rProp
, getContentType () );
614 else if ( rProp
.Name
== "IsDocument" ) {
615 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
616 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_REGULAR
||
617 m_info
.type
== GNOME_VFS_FILE_TYPE_UNKNOWN
) );
619 xRow
->appendVoid( rProp
);
621 else if ( rProp
.Name
== "IsFolder" ) {
622 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
623 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) );
625 xRow
->appendVoid( rProp
);
627 else if ( rProp
.Name
== "IsReadOnly" ) {
629 GnomeVFSFileInfo
* fileInfo
= gnome_vfs_file_info_new ();
631 ::rtl::OString aURI
= getOURI();
632 gnome_vfs_get_file_info
633 ( aURI
.getStr(), fileInfo
,
634 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
);
636 if (fileInfo
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_ACCESS
) {
637 bool read_only
= true;
639 if (fileInfo
->permissions
& GNOME_VFS_PERM_ACCESS_WRITABLE
)
642 xRow
->appendBoolean( rProp
, read_only
);
644 xRow
->appendVoid( rProp
);
645 gnome_vfs_file_info_unref (fileInfo
);
647 else if ( rProp
.Name
== "Size" ) {
648 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
)
649 xRow
->appendLong( rProp
, m_info
.size
);
651 xRow
->appendVoid( rProp
);
653 else if ( rProp
.Name
== "IsHidden" )
654 xRow
->appendBoolean( rProp
, ( m_info
.name
&& m_info
.name
[0] == '.' ) );
656 else if (rProp
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsVolume" ) ) ||
657 rProp
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsCompactDisk" ) ) )
658 xRow
->appendBoolean( rProp
, sal_False
);
660 else if ( rProp
.Name
== "DateCreated" ) {
661 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_CTIME
)
662 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.ctime
) );
664 xRow
->appendVoid( rProp
);
667 else if ( rProp
.Name
== "DateModified" ) {
668 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
669 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.mtime
) );
671 xRow
->appendVoid( rProp
);
674 else if ( rProp
.Name
== "MediaType" ) {
675 // We do this by sniffing in gnome-vfs; rather expensively.
677 g_warning ("FIXME: Requested mime-type - an expensive op. indeed!");
679 xRow
->appendVoid( rProp
);
680 } else if ( rProp
.Name
== "CreatableContentsInfo" )
681 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
684 xRow
->appendVoid( rProp
);
687 #if OSL_DEBUG_LEVEL > 1
688 g_warning ("getPropertyValues on '%s' %d properties returned (of %d)",
689 getURI(), 0, (int)nProps
);
692 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
695 static lang::IllegalAccessException
696 getReadOnlyException( Content
*ctnt
)
698 return lang::IllegalAccessException
699 ( rtl::OUString("Property is read-only!"),
700 static_cast< cppu::OWeakObject
* >( ctnt
) );
704 Content::makeNewURL( const char */
*newName*/
)
706 rtl::OUString aNewURL
= getParentURL();
707 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
708 aNewURL
+= rtl::OUString("/");
710 char *name
= gnome_vfs_escape_string( m_info
.name
);
711 aNewURL
+= GnomeToOUString( name
);
717 // This is slightly complicated by needing to support either 'move' or 'setname'
719 Content::doSetFileInfo( const GnomeVFSFileInfo
*newInfo
,
720 GnomeVFSSetFileInfoMask setMask
,
721 const uno::Reference
< ucb::XCommandEnvironment
>& /*xEnv*/ )
723 GnomeVFSResult result
= GNOME_VFS_OK
;
725 g_assert (!m_bTransient
);
727 ::rtl::OString aURI
= getOURI();
729 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
731 // The simple approach:
732 if( setMask
!= GNOME_VFS_SET_FILE_INFO_NONE
)
733 result
= gnome_vfs_set_file_info
// missed a const in the API there
734 ( aURI
.getStr(), (GnomeVFSFileInfo
*)newInfo
, setMask
);
736 if ( result
== GNOME_VFS_ERROR_NOT_SUPPORTED
&&
737 ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) ) {
738 // Try a move instead
740 g_warning( "SetFileInfo not supported on '%s'", getURI() );
743 char *newURI
= OUStringToGnome( makeNewURL( newInfo
->name
) );
745 result
= gnome_vfs_move (aURI
.getStr(), newURI
, FALSE
);
754 uno::Sequence
< uno::Any
> Content::setPropertyValues(
755 const uno::Sequence
< beans::PropertyValue
>& rValues
,
756 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
758 rtl::OUString aNewTitle
;
759 GnomeVFSFileInfo newInfo
;
760 int setMask
= GNOME_VFS_SET_FILE_INFO_NONE
;
764 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
766 gnome_vfs_file_info_copy( &newInfo
, &m_info
);
768 Authentication
aAuth( xEnv
);
770 int nChanged
= 0, nTitlePos
= 0;
771 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
772 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
774 beans::PropertyChangeEvent aEvent
;
775 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
776 aEvent
.Further
= sal_False
;
777 aEvent
.PropertyHandle
= -1;
778 // aEvent.PropertyName = fill in later ...
782 int nCount
= rValues
.getLength();
783 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
785 for ( sal_Int32 n
= 0; n
< nCount
; ++n
) {
786 const beans::PropertyValue
& rValue
= pValues
[ n
];
788 #if OSL_DEBUG_LEVEL > 1
789 g_warning( "Set prop '%s'", OUStringToGnome( rValue
.Name
) );
791 if ( rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ||
792 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ||
793 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ||
794 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ||
795 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ||
796 rValue
.Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
797 aRet
[ n
] <<= getReadOnlyException( this );
799 else if ( rValue
.Name
== "Title" ) {
800 if ( rValue
.Value
>>= aNewTitle
) {
801 if ( aNewTitle
.isEmpty() )
802 aRet
[ n
] <<= lang::IllegalArgumentException
803 ( rtl::OUString("Empty title not allowed!"),
804 static_cast< cppu::OWeakObject
* >( this ), -1 );
806 char *newName
= OUStringToGnome( aNewTitle
);
808 if( !newName
|| !m_info
.name
|| strcmp( newName
, m_info
.name
) ) {
809 #if OSL_DEBUG_LEVEL > 1
810 g_warning ("Set new name to '%s'", newName
);
813 aEvent
.PropertyName
= rtl::OUString("Title");
814 aEvent
.OldValue
= uno::makeAny( GnomeToOUString( newInfo
.name
) );
815 aEvent
.NewValue
= uno::makeAny( aNewTitle
);
816 aChanges
.getArray()[ nChanged
] = aEvent
;
817 nTitlePos
= nChanged
++;
819 newInfo
.name
= newName
;
820 setMask
|= GNOME_VFS_SET_FILE_INFO_NAME
;
825 aRet
[ n
] <<= beans::IllegalTypeException
826 ( rtl::OUString("Property value has wrong type!"),
827 static_cast< cppu::OWeakObject
* >( this ) );
829 } else if ( rValue
.Name
== "DateCreated" || rValue
.Name
== "DateModified" ) {
830 // FIXME: should be able to set the timestamps
831 aRet
[ n
] <<= getReadOnlyException( this );
834 g_warning( "Unhandled property '%s'", OUStringToGnome( rValue
.Name
) );
836 aRet
[ n
] <<= getReadOnlyException( this );
840 GnomeVFSResult result
= GNOME_VFS_OK
;
842 if ( !m_bTransient
&&
843 ( result
= doSetFileInfo( &newInfo
,
844 (GnomeVFSSetFileInfoMask
) setMask
,
845 xEnv
) ) != GNOME_VFS_OK
) {
846 for (int i
= 0; i
< nChanged
; i
++)
847 aRet
[ i
] <<= mapVFSException( result
, sal_True
);
851 if ( result
== GNOME_VFS_OK
) {
852 gnome_vfs_file_info_copy( &m_info
, &newInfo
);
854 if ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) {
855 uno::Reference
< ucb::XContentIdentifier
> xNewId
856 = new ::ucbhelper::ContentIdentifier( makeNewURL( newInfo
.name
) );
859 if (!exchangeIdentity( xNewId
) )
860 aRet
[ nTitlePos
] <<= uno::Exception
861 ( rtl::OUString("Exchange failed!"),
862 static_cast< cppu::OWeakObject
* >( this ) );
866 gnome_vfs_file_info_clear( &newInfo
);
868 if ( nChanged
> 0 ) {
870 aChanges
.realloc( nChanged
);
871 notifyPropertiesChange( aChanges
);
877 void Content::queryChildren( ContentRefList
& rChildren
)
879 // Obtain a list with a snapshot of all currently instanciated contents
880 // from provider and extract the contents which are direct children
883 ::ucbhelper::ContentRefList aAllContents
;
884 m_xProvider
->queryExistingContents( aAllContents
);
886 rtl::OUString aURL
= getOUURI();
887 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
889 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
890 aURL
+= rtl::OUString("/");
892 sal_Int32 nLen
= aURL
.getLength();
894 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
895 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
897 while ( it
!= end
) {
898 ::ucbhelper::ContentImplHelperRef xChild
= (*it
);
899 rtl::OUString aChildURL
900 = xChild
->getIdentifier()->getContentIdentifier();
902 // Is aURL a prefix of aChildURL?
903 if ( ( aChildURL
.getLength() > nLen
) &&
904 ( aChildURL
.compareTo( aURL
, nLen
) == 0 ) ) {
905 sal_Int32 nPos
= nLen
;
906 nPos
= aChildURL
.indexOf( '/', nPos
);
908 if ( ( nPos
== -1 ) ||
909 ( nPos
== ( aChildURL
.getLength() - 1 ) ) ) {
910 // No further slashes / only a final slash. It's a child!
911 rChildren
.push_back( ::gvfs::Content::ContentRef
912 (static_cast< ::gvfs::Content
* >(xChild
.get() ) ) );
919 void Content::insert(
920 const uno::Reference
< io::XInputStream
> &xInputStream
,
921 sal_Bool bReplaceExisting
,
922 const uno::Reference
< ucb::XCommandEnvironment
> &xEnv
)
923 throw( uno::Exception
)
925 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
927 #if OSL_DEBUG_LEVEL > 1
928 g_warning( "Insert '%s' (%d) (0x%x:%d)", getURI(), bReplaceExisting
,
929 m_info
.valid_fields
, m_info
.type
);
932 GnomeVFSResult result
= getInfo( xEnv
);
933 // a racy design indeed.
934 if( !bReplaceExisting
&& !m_bTransient
&&
935 result
!= GNOME_VFS_ERROR_NOT_FOUND
) {
937 g_warning ("Nasty error inserting to '%s' ('%s')",
938 getURI(), gnome_vfs_result_to_string( result
));
940 cancelCommandExecution( GNOME_VFS_ERROR_FILE_EXISTS
, xEnv
, sal_True
);
943 if ( m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
944 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) {
945 ::rtl::OString aURI
= getOURI();
948 perm
= ( GNOME_VFS_PERM_USER_ALL
|
949 GNOME_VFS_PERM_GROUP_READ
|
950 GNOME_VFS_PERM_OTHER_READ
);
952 #if OSL_DEBUG_LEVEL > 1
953 g_warning ("Make directory");
955 result
= gnome_vfs_make_directory( aURI
.getStr(), perm
);
957 if( result
!= GNOME_VFS_OK
)
958 cancelCommandExecution( result
, xEnv
, sal_True
);
963 if ( !xInputStream
.is() ) {
964 // FIXME: slightly unclear whether to accept this and create an empty file
965 ucbhelper::cancelCommandExecution
967 ( ucb::MissingInputStreamException
969 static_cast< cppu::OWeakObject
* >( this ) ) ),
973 GnomeVFSHandle
*handle
= NULL
;
974 ::rtl::OString aURI
= getOURI();
976 result
= GNOME_VFS_OK
;
977 if ( bReplaceExisting
) {
978 Authentication
aAuth( xEnv
);
979 result
= gnome_vfs_open( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
);
982 if ( result
!= GNOME_VFS_OK
) {
984 Authentication
aAuth( xEnv
);
986 perm
= ( ( GNOME_VFS_PERM_USER_WRITE
| GNOME_VFS_PERM_USER_READ
) |
987 ( GNOME_VFS_PERM_GROUP_WRITE
| GNOME_VFS_PERM_GROUP_READ
) );
989 result
= gnome_vfs_create
990 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
, TRUE
, perm
);
993 if( result
!= GNOME_VFS_OK
)
994 cancelCommandExecution( result
, xEnv
, sal_True
);
996 if ( !xInputStream
.is() ) {
997 result
= gnome_vfs_close( handle
);
998 if (result
!= GNOME_VFS_OK
)
999 cancelCommandExecution( result
, xEnv
, sal_True
);
1001 } else { // copy it over
1002 uno::Reference
< io::XOutputStream
> xOutput
=
1003 new gvfs::Stream( handle
, &m_info
);
1005 copyData( xInputStream
, xOutput
);
1009 m_bTransient
= sal_False
;
1015 void Content::transfer(const ucb::TransferInfo
& /*rArgs*/,
1016 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1017 throw( uno::Exception
)
1019 // FIXME: see gnome-vfs-xfer.h - but we need to be able to easily
1020 // detect which are gnome-vfs owned URI types ...
1021 ucbhelper::cancelCommandExecution
1023 ( ucb::InteractiveBadTransferURLException
1024 ( rtl::OUString("Unsupported URL scheme!"),
1025 static_cast< cppu::OWeakObject
* >( this ) ) ),
1029 void Content::destroy( sal_Bool bDeletePhysical
)
1030 throw( uno::Exception
)
1032 // @@@ take care about bDeletePhysical -> trashcan support
1033 uno::Reference
< ucb::XContent
> xThis
= this;
1037 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1039 // Process instanciated children...
1040 ::gvfs::Content::ContentRefList aChildren
;
1041 queryChildren( aChildren
);
1043 ContentRefList::const_iterator it
= aChildren
.begin();
1044 ContentRefList::const_iterator end
= aChildren
.end();
1046 while ( it
!= end
) {
1047 (*it
)->destroy( bDeletePhysical
);
1052 // Used by the 'setPropertyValues' method for
1053 // propagating the renaming of a Content.
1054 sal_Bool
Content::exchangeIdentity(
1055 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1060 uno::Reference
< ucb::XContent
> xThis
= this;
1062 #if OSL_DEBUG_LEVEL > 1
1063 g_warning( "exchangeIdentity from '%s' to '%s'",
1064 getURI(), OUStringToGnome( xNewId
->getContentIdentifier() ) );
1067 if ( m_bTransient
) {
1068 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1069 /* FIXME: can we not screw up an identically named
1070 * Content pointing to ourself here ? */
1071 m_xIdentifier
= xNewId
;
1075 rtl::OUString aOldURL
= getOUURI();
1077 // Exchange own identitity.
1078 if ( exchange( xNewId
) ) {
1080 // Process instanciated children...
1081 ContentRefList aChildren
;
1082 queryChildren( aChildren
);
1084 ContentRefList::const_iterator it
= aChildren
.begin();
1085 ContentRefList::const_iterator end
= aChildren
.end();
1087 while ( it
!= end
) {
1088 ContentRef xChild
= (*it
);
1090 // Create new content identifier for the child...
1091 uno::Reference
< ucb::XContentIdentifier
>
1092 xOldChildId
= xChild
->getIdentifier();
1093 rtl::OUString aOldChildURL
1094 = xOldChildId
->getContentIdentifier();
1095 rtl::OUString aNewChildURL
1096 = aOldChildURL
.replaceAt(
1098 aOldURL
.getLength(),
1099 xNewId
->getContentIdentifier() );
1100 uno::Reference
< ucb::XContentIdentifier
>
1102 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1104 if ( !xChild
->exchangeIdentity( xNewChildId
) )
1116 Content::getInfo( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1118 GnomeVFSResult result
;
1119 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1122 result
= GNOME_VFS_OK
;
1124 else if ( !m_info
.valid_fields
) {
1125 ::rtl::OString aURI
= getOURI();
1126 Authentication
aAuth( xEnv
);
1127 result
= gnome_vfs_get_file_info
1128 ( aURI
.getStr(), &m_info
, GNOME_VFS_FILE_INFO_DEFAULT
);
1129 if (result
!= GNOME_VFS_OK
)
1130 gnome_vfs_file_info_clear( &m_info
);
1132 result
= GNOME_VFS_OK
;
1133 #if OSL_DEBUG_LEVEL > 1
1134 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)",
1135 getURI(), gnome_vfs_result_to_string( result
),
1136 result
, m_info
.valid_fields
);
1142 Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1144 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1146 return (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
1147 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
);
1150 uno::Any
Content::mapVFSException( const GnomeVFSResult result
, sal_Bool bWrite
)
1152 uno::Any aException
;
1153 const char *gvfs_message
;
1154 rtl::OUString message
;
1155 uno::Sequence
< uno::Any
> aArgs( 1 );
1157 #if OSL_DEBUG_LEVEL > 1
1158 g_warning ("Map VFS exception '%s' (%d)",
1159 gnome_vfs_result_to_string( result
), result
);
1162 if ((gvfs_message
= gnome_vfs_result_to_string (result
)))
1163 message
= GnomeToOUString( gvfs_message
);
1167 g_warning("VFS_OK mapped to exception.");
1169 case GNOME_VFS_ERROR_EOF
:
1170 g_warning ("VFS_EOF not handled somewhere.");
1172 case GNOME_VFS_ERROR_NOT_FOUND
:
1173 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
1175 ucb::InteractiveAugmentedIOException
1176 ( rtl::OUString("Not found!"),
1177 static_cast< cppu::OWeakObject
* >( this ),
1178 task::InteractionClassification_ERROR
,
1179 ucb::IOErrorCode_NOT_EXISTING
,
1182 case GNOME_VFS_ERROR_BAD_PARAMETERS
:
1184 lang::IllegalArgumentException
1186 static_cast< cppu::OWeakObject
* >( this ),
1189 case GNOME_VFS_ERROR_GENERIC
:
1190 case GNOME_VFS_ERROR_INTERNAL
:
1191 case GNOME_VFS_ERROR_NOT_SUPPORTED
:
1193 g_warning ("Internal - un-mapped error");
1195 aException
<<= io::IOException();
1197 case GNOME_VFS_ERROR_IO
:
1200 ucb::InteractiveNetworkWriteException
1202 static_cast< cppu::OWeakObject
* >( this ),
1203 task::InteractionClassification_ERROR
,
1207 ucb::InteractiveNetworkReadException
1209 static_cast< cppu::OWeakObject
* >( this ),
1210 task::InteractionClassification_ERROR
,
1213 case GNOME_VFS_ERROR_HOST_NOT_FOUND
:
1214 case GNOME_VFS_ERROR_INVALID_HOST_NAME
:
1216 ucb::InteractiveNetworkResolveNameException
1218 static_cast< cppu::OWeakObject
* >( this ),
1219 task::InteractionClassification_ERROR
,
1222 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
:
1223 case GNOME_VFS_ERROR_SERVICE_OBSOLETE
:
1224 case GNOME_VFS_ERROR_PROTOCOL_ERROR
:
1225 case GNOME_VFS_ERROR_NO_MASTER_BROWSER
:
1227 ucb::InteractiveNetworkConnectException
1229 static_cast< cppu::OWeakObject
* >( this ),
1230 task::InteractionClassification_ERROR
,
1234 case GNOME_VFS_ERROR_FILE_EXISTS
:
1235 aException
<<= ucb::NameClashException
1237 static_cast< cppu::OWeakObject
* >( this ),
1238 task::InteractionClassification_ERROR
,
1242 case GNOME_VFS_ERROR_INVALID_OPEN_MODE
:
1243 aException
<<= ucb::UnsupportedOpenModeException();
1246 case GNOME_VFS_ERROR_CORRUPTED_DATA
:
1247 case GNOME_VFS_ERROR_WRONG_FORMAT
:
1248 case GNOME_VFS_ERROR_BAD_FILE
:
1249 case GNOME_VFS_ERROR_TOO_BIG
:
1250 case GNOME_VFS_ERROR_NO_SPACE
:
1251 case GNOME_VFS_ERROR_READ_ONLY
:
1252 case GNOME_VFS_ERROR_INVALID_URI
:
1253 case GNOME_VFS_ERROR_NOT_OPEN
:
1254 case GNOME_VFS_ERROR_ACCESS_DENIED
:
1255 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES
:
1256 case GNOME_VFS_ERROR_NOT_A_DIRECTORY
:
1257 case GNOME_VFS_ERROR_IN_PROGRESS
:
1258 case GNOME_VFS_ERROR_INTERRUPTED
:
1259 case GNOME_VFS_ERROR_LOOP
:
1260 case GNOME_VFS_ERROR_NOT_PERMITTED
:
1261 case GNOME_VFS_ERROR_IS_DIRECTORY
:
1262 case GNOME_VFS_ERROR_NO_MEMORY
:
1263 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS
:
1264 case GNOME_VFS_ERROR_LOGIN_FAILED
:
1265 case GNOME_VFS_ERROR_CANCELLED
:
1266 case GNOME_VFS_ERROR_DIRECTORY_BUSY
:
1267 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY
:
1268 case GNOME_VFS_ERROR_TOO_MANY_LINKS
:
1269 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM
:
1270 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM
:
1271 case GNOME_VFS_ERROR_NAME_TOO_LONG
:
1273 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)",
1274 gnome_vfs_result_to_string( result
), result
);
1277 aException
<<= ucb::InteractiveNetworkGeneralException
1279 static_cast< cppu::OWeakObject
* >( this ),
1280 task::InteractionClassification_ERROR
);
1287 void Content::cancelCommandExecution(
1288 GnomeVFSResult result
,
1289 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1290 sal_Bool bWrite
/* = sal_False */ )
1291 throw ( uno::Exception
)
1293 ucbhelper::cancelCommandExecution( mapVFSException( result
, bWrite
), xEnv
);
1297 uno::Sequence
< beans::Property
> Content::getProperties(
1298 const uno::Reference
< ucb::XCommandEnvironment
> & /*xEnv*/ )
1300 static const beans::Property aGenericProperties
[] = {
1301 beans::Property( rtl::OUString( "ContentType" ),
1302 -1, getCppuType( static_cast< const rtl::OUString
* >( 0 ) ),
1303 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1304 beans::Property( rtl::OUString( "IsDocument" ),
1305 -1, getCppuBooleanType(),
1306 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1307 beans::Property( rtl::OUString( "IsFolder" ),
1308 -1, getCppuBooleanType(),
1309 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1310 beans::Property( rtl::OUString( "Title" ),
1311 -1, getCppuType( static_cast< const rtl::OUString
* >( 0 ) ),
1312 beans::PropertyAttribute::BOUND
),
1314 beans::Property( rtl::OUString( "DateCreated" ),
1315 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1316 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1317 beans::Property( rtl::OUString( "DateModified" ),
1318 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1319 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1320 // FIXME: Too expensive for now (?)
1321 // beans::Property( rtl::OUString( "MediaType" ),
1322 // -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1323 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1324 beans::Property( rtl::OUString( "Size" ),
1325 -1, getCppuType( static_cast< const sal_Int64
* >( 0 ) ),
1326 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1327 beans::Property( rtl::OUString( "IsReadOnly" ),
1328 -1, getCppuBooleanType(),
1329 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1330 beans::Property( rtl::OUString( "IsVolume" ),
1331 -1, getCppuBooleanType(),
1332 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1333 beans::Property( rtl::OUString( "IsCompactDisk" ),
1334 -1, getCppuBooleanType(),
1335 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1336 beans::Property( rtl::OUString( "IsHidden" ),
1337 -1, getCppuBooleanType(),
1338 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1339 beans::Property( rtl::OUString( "CreatableContentsInfo" ),
1340 -1, getCppuType( static_cast< const uno::Sequence
< ucb::ContentInfo
> * >( 0 ) ),
1341 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
)
1344 const int nProps
= sizeof (aGenericProperties
) / sizeof (aGenericProperties
[0]);
1346 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1350 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1351 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1353 static ucb::CommandInfo aCommandInfoTable
[] = {
1354 // Required commands
1356 ( rtl::OUString( "getCommandInfo" ),
1357 -1, getCppuVoidType() ),
1359 ( rtl::OUString( "getPropertySetInfo" ),
1360 -1, getCppuVoidType() ),
1362 ( rtl::OUString( "getPropertyValues" ),
1363 -1, getCppuType( static_cast<uno::Sequence
< beans::Property
> * >( 0 ) ) ),
1365 ( rtl::OUString( "setPropertyValues" ),
1366 -1, getCppuType( static_cast<uno::Sequence
< beans::PropertyValue
> * >( 0 ) ) ),
1368 // Optional standard commands
1370 ( rtl::OUString( "delete" ),
1371 -1, getCppuBooleanType() ),
1373 ( rtl::OUString( "insert" ),
1374 -1, getCppuType( static_cast<ucb::InsertCommandArgument
* >( 0 ) ) ),
1376 ( rtl::OUString( "open" ),
1377 -1, getCppuType( static_cast<ucb::OpenCommandArgument2
* >( 0 ) ) ),
1379 // Folder Only, omitted if not a folder
1381 ( rtl::OUString( "transfer" ),
1382 -1, getCppuType( static_cast<ucb::TransferInfo
* >( 0 ) ) ),
1384 ( rtl::OUString( "createNewContent" ),
1385 -1, getCppuType( static_cast<ucb::ContentInfo
* >( 0 ) ) )
1389 = sizeof( aCommandInfoTable
) / sizeof( aCommandInfoTable
[ 0 ] );
1390 return uno::Sequence
< ucb::CommandInfo
>(
1391 aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2 );
1395 Content::getOUURI ()
1397 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1398 return m_xIdentifier
->getContentIdentifier();
1404 return rtl::OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8
);
1410 return OUStringToGnome( getOUURI() );
1414 Content::copyData( uno::Reference
< io::XInputStream
> xIn
,
1415 uno::Reference
< io::XOutputStream
> xOut
)
1417 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1419 g_return_if_fail( xIn
.is() && xOut
.is() );
1421 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1422 xOut
->writeBytes( theData
);
1424 xOut
->closeOutput();
1427 // Inherits an authentication context
1428 uno::Reference
< io::XInputStream
>
1429 Content::createTempStream(
1430 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1431 throw( uno::Exception
)
1433 GnomeVFSResult result
;
1434 GnomeVFSHandle
*handle
= NULL
;
1435 ::rtl::OString aURI
= getOURI();
1437 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1438 // Something badly wrong happened - can't seek => stream to a temporary file
1439 uno::Reference
< io::XOutputStream
> xTempOut
=
1440 uno::Reference
< io::XOutputStream
>
1441 ( io::TempFile::create( m_xContext
), uno::UNO_QUERY
);
1443 if ( !xTempOut
.is() )
1444 cancelCommandExecution( GNOME_VFS_ERROR_IO
, xEnv
);
1446 result
= gnome_vfs_open
1447 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_READ
);
1448 if (result
!= GNOME_VFS_OK
)
1449 cancelCommandExecution( result
, xEnv
);
1451 uno::Reference
< io::XInputStream
> pStream
= new ::gvfs::Stream( handle
, &m_info
);
1452 copyData( pStream
, xTempOut
);
1454 return uno::Reference
< io::XInputStream
> ( xTempOut
, uno::UNO_QUERY
);
1457 uno::Reference
< io::XInputStream
>
1458 Content::createInputStream(
1459 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1460 throw( uno::Exception
)
1462 GnomeVFSHandle
*handle
= NULL
;
1463 GnomeVFSResult result
;
1464 uno::Reference
<io::XInputStream
> xIn
;
1466 Authentication
aAuth( xEnv
);
1467 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1470 ::rtl::OString aURI
= getOURI();
1472 if ( !(m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
) )
1473 return createTempStream( xEnv
);
1475 result
= gnome_vfs_open
1476 ( &handle
, aURI
.getStr(),
1477 (GnomeVFSOpenMode
) (GNOME_VFS_OPEN_READ
| GNOME_VFS_OPEN_RANDOM
) );
1479 if (result
== GNOME_VFS_ERROR_INVALID_OPEN_MODE
||
1480 result
== GNOME_VFS_ERROR_NOT_SUPPORTED
)
1481 return createTempStream( xEnv
);
1483 if (result
!= GNOME_VFS_OK
)
1484 cancelCommandExecution( result
, xEnv
);
1486 // Try a seek just to make sure it's Random access: some lie.
1487 result
= gnome_vfs_seek( handle
, GNOME_VFS_SEEK_START
, 0);
1488 if (result
== GNOME_VFS_ERROR_NOT_SUPPORTED
) {
1489 gnome_vfs_close( handle
);
1490 return createTempStream( xEnv
);
1493 if (result
!= GNOME_VFS_OK
)
1494 cancelCommandExecution( result
, xEnv
);
1497 xIn
= new ::gvfs::Stream( handle
, &m_info
);
1503 Content::feedSink( uno::Reference
< uno::XInterface
> aSink
,
1504 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1509 uno::Reference
< io::XOutputStream
> xOut
1510 = uno::Reference
< io::XOutputStream
>(aSink
, uno::UNO_QUERY
);
1511 uno::Reference
< io::XActiveDataSink
> xDataSink
1512 = uno::Reference
< io::XActiveDataSink
>(aSink
, uno::UNO_QUERY
);
1514 if ( !xOut
.is() && !xDataSink
.is() )
1517 uno::Reference
< io::XInputStream
> xIn
= createInputStream( xEnv
);
1522 copyData( xIn
, xOut
);
1524 if ( xDataSink
.is() )
1525 xDataSink
->setInputStream( xIn
);
1532 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
1533 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)"
1537 vfs_authentication_callback (gconstpointer in_void
,
1541 gpointer callback_data
)
1543 task::XInteractionHandler
*xIH
;
1545 #if OSL_DEBUG_LEVEL > 1
1546 g_warning ("Full authentication callback (%p) ...", callback_data
);
1549 if( !( xIH
= (task::XInteractionHandler
*) callback_data
) )
1552 const GnomeVFSModuleCallbackFullAuthenticationIn
*in
=
1553 (const GnomeVFSModuleCallbackFullAuthenticationIn
*) in_void
;
1554 GnomeVFSModuleCallbackFullAuthenticationOut
*out
=
1555 (GnomeVFSModuleCallbackFullAuthenticationOut
*) out_void
;
1557 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1558 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn
) == in_size
&&
1559 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut
) == out_size
);
1561 #if OSL_DEBUG_LEVEL > 1
1562 # define NNIL(x) (x?x:"<Null>")
1563 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' "
1564 "port %d auth_t '%s' user '%s' domain '%s' "
1565 "def user '%s', def domain '%s'",
1566 (int) in
->flags
, NNIL(in
->uri
), NNIL(in
->protocol
),
1567 NNIL(in
->server
), NNIL(in
->object
),
1568 (int) in
->port
, NNIL(in
->authtype
), NNIL(in
->username
), NNIL(in
->domain
),
1569 NNIL(in
->default_user
), NNIL(in
->default_domain
));
1573 ucbhelper::SimpleAuthenticationRequest::EntityType
1574 eDomain
, eUserName
, ePassword
;
1575 ::rtl::OUString aHostName
, aDomain
, aUserName
, aPassword
;
1577 aHostName
= GnomeToOUString( in
->server
);
1579 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
)
1581 aDomain
= GnomeToOUString( in
->domain
);
1582 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
;
1583 if (aDomain
.isEmpty())
1584 aDomain
= GnomeToOUString( in
->default_domain
);
1586 else // no underlying capability to display realm otherwise
1587 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
;
1589 aUserName
= GnomeToOUString( in
->username
);
1590 if (aUserName
.isEmpty())
1591 aUserName
= GnomeToOUString( in
->default_user
);
1592 eUserName
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
) ?
1593 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1594 (!aUserName
.isEmpty() ?
1595 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
:
1596 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
);
1598 // No suggested password.
1599 ePassword
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
) ?
1600 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1601 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
;
1603 // Really, really bad things happen if we don't provide
1604 // the same user/password as was entered last time if
1605 // we failed to authenticate - infinite looping / flickering
1606 // madness etc. [ nice infrastructure ! ]
1607 static rtl::OUString aLastUserName
, aLastPassword
;
1608 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
)
1610 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1611 aUserName
= aLastUserName
;
1612 aPassword
= aLastPassword
;
1615 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
1616 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in
->uri
),
1617 aHostName
, eDomain
, aDomain
,
1618 eUserName
, aUserName
,
1619 ePassword
, aPassword
);
1621 xIH
->handle( xRequest
.get() );
1623 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
1624 = xRequest
->getSelection();
1626 if ( xSelection
.is() ) {
1627 // Handler handled the request.
1628 uno::Reference
< task::XInteractionAbort
> xAbort(xSelection
.get(), uno::UNO_QUERY
);
1629 if ( !xAbort
.is() ) {
1630 const rtl::Reference
<
1631 ucbhelper::InteractionSupplyAuthentication
> & xSupp
1632 = xRequest
->getAuthenticationSupplier();
1634 ::rtl::OUString aNewDomain
, aNewUserName
, aNewPassword
;
1636 aNewUserName
= xSupp
->getUserName();
1637 if ( !aNewUserName
.isEmpty() )
1638 aUserName
= aNewUserName
;
1639 aNewDomain
= xSupp
->getRealm();
1640 if ( !aNewDomain
.isEmpty() )
1641 aDomain
= aNewDomain
;
1642 aNewPassword
= xSupp
->getPassword();
1643 if ( !aNewPassword
.isEmpty() )
1644 aPassword
= aNewPassword
;
1647 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1648 aLastUserName
= aUserName
;
1649 aLastPassword
= aPassword
;
1652 out
->username
= OUStringToGnome( aUserName
);
1653 out
->domain
= OUStringToGnome( aDomain
);
1654 out
->password
= OUStringToGnome( aPassword
);
1655 out
->save_password
= xSupp
->getRememberPasswordMode();
1657 #if OSL_DEBUG_LEVEL > 1
1658 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password",
1659 out
->username
, out
->domain
, out
->password
,
1660 out
->save_password
? "save" : "don't save");
1664 out
->abort_auth
= TRUE
;
1667 out
->abort_auth
= TRUE
;
1671 vfs_authentication_old_callback (gconstpointer in_void
,
1675 gpointer callback_data
)
1678 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data
);
1680 const GnomeVFSModuleCallbackAuthenticationIn
*in
=
1681 (const GnomeVFSModuleCallbackAuthenticationIn
*) in_void
;
1682 GnomeVFSModuleCallbackAuthenticationOut
*out
=
1683 (GnomeVFSModuleCallbackAuthenticationOut
*) out_void
;
1685 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1686 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn
) == in_size
&&
1687 sizeof (GnomeVFSModuleCallbackAuthenticationOut
) == out_size
);
1689 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in
= {
1690 (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1691 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
|
1692 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
|
1693 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
),
1694 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1695 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out
= { 0, 0, 0, 0, 0, 0, 0, 0 };
1697 // Map the old style input auth. data to the new style structure.
1698 if (in
->previous_attempt_failed
)
1699 mapped_in
.flags
= (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1701 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
);
1703 GnomeVFSURI
*pURI
= NULL
;
1704 // Urk - parse all this from the URL ...
1705 mapped_in
.uri
= in
->uri
;
1708 pURI
= gnome_vfs_uri_new( in
->uri
);
1709 mapped_in
.protocol
= (char *) gnome_vfs_uri_get_scheme (pURI
);
1710 mapped_in
.server
= (char *) gnome_vfs_uri_get_host_name (pURI
);
1711 mapped_in
.port
= gnome_vfs_uri_get_host_port (pURI
);
1712 mapped_in
.username
= (char *) gnome_vfs_uri_get_user_name (pURI
);
1714 mapped_in
.domain
= in
->realm
;
1715 mapped_in
.default_user
= mapped_in
.username
;
1716 mapped_in
.default_domain
= mapped_in
.domain
;
1718 vfs_authentication_callback ((gconstpointer
) &mapped_in
,
1720 (gpointer
) &mapped_out
,
1721 sizeof (mapped_out
),
1725 gnome_vfs_uri_unref (pURI
);
1727 // Map the new style auth. out data to the old style out structure.
1728 out
->username
= mapped_out
.username
;
1729 out
->password
= mapped_out
.password
;
1730 g_free (mapped_out
.domain
);
1731 g_free (mapped_out
.keyring
);
1736 auth_destroy (gpointer data
)
1738 task::XInteractionHandler
*xIH
;
1739 if( ( xIH
= ( task::XInteractionHandler
* )data
) )
1743 // This sucks, but gnome-vfs doesn't much like
1744 // repeated set / unsets - so we have to compensate.
1745 GPrivate
*auth_queue
= NULL
;
1747 void auth_queue_destroy( gpointer data
)
1750 GQueue
*vq
= (GQueue
*) data
;
1752 for (l
= vq
->head
; l
; l
= l
->next
)
1753 auth_destroy (l
->data
);
1759 refresh_auth( GQueue
*vq
)
1763 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
);
1764 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
);
1766 for (l
= vq
->head
; l
; l
= l
->next
) {
1768 gnome_vfs_module_callback_push
1769 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
,
1770 vfs_authentication_old_callback
, l
->data
, NULL
);
1771 gnome_vfs_module_callback_push
1772 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
,
1773 vfs_authentication_callback
, l
->data
, NULL
);
1779 gvfs::Authentication::Authentication(
1780 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1783 uno::Reference
< task::XInteractionHandler
> xIH
;
1786 xIH
= xEnv
->getInteractionHandler();
1791 if( !(vq
= (GQueue
*)g_private_get( auth_queue
) ) ) {
1793 g_private_set( auth_queue
, vq
);
1796 g_queue_push_head( vq
, (gpointer
) xIH
.get() );
1800 gvfs::Authentication::~Authentication()
1805 vq
= (GQueue
*)g_private_get( auth_queue
);
1807 data
= g_queue_pop_head( vq
);
1808 auth_destroy (data
);
1813 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */