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 <comphelper/processfactory.hxx>
62 #include <ucbhelper/contentidentifier.hxx>
63 #include <ucbhelper/propertyvalueset.hxx>
64 #include <ucbhelper/interactionrequest.hxx>
65 #include <ucbhelper/cancelcommandexecution.hxx>
66 #include <ucbhelper/simpleauthenticationrequest.hxx>
68 const int TRANSFER_BUFFER_SIZE
= 65536;
71 * NB. Name escaping is done only for URIs
72 * the 'Title' property is unescaped on set/get
74 #include <libgnomevfs/gnome-vfs-utils.h>
75 #include <libgnomevfs/gnome-vfs-result.h>
76 #include <libgnomevfs/gnome-vfs-standard-callbacks.h>
77 extern "C" { // missing in the header: doh.
78 # include <libgnomevfs/gnome-vfs-module-callback.h>
81 #include "gvfs_content.hxx"
82 #include "gvfs_provider.hxx"
83 #include "gvfs_directory.hxx"
84 #include "gvfs_stream.hxx"
87 using namespace com::sun::star
;
89 #define CLEAR_INFO(info) memset((info), 0, sizeof ((info)[0]))
93 OUStringToGnome( const OUString
&str
)
95 OString aTempStr
= OUStringToOString( str
, RTL_TEXTENCODING_UTF8
);
96 return g_strdup( aTempStr
.getStr() );
100 GnomeToOUString( const char *utf8_str
)
105 return OUString( utf8_str
, strlen( utf8_str
), RTL_TEXTENCODING_UTF8
);
110 const uno::Reference
< uno::XComponentContext
>& rxContext
,
111 ContentProvider
* pProvider
,
112 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
113 throw ( ucb::ContentCreationException
)
114 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
115 m_pProvider( pProvider
),
116 m_bTransient( sal_False
)
118 CLEAR_INFO (&m_info
);
119 #if OSL_DEBUG_LEVEL > 1
120 g_warning ("New Content ('%s')", getURI());
125 const uno::Reference
< uno::XComponentContext
>& rxContext
,
126 ContentProvider
* pProvider
,
127 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
129 throw ( ucb::ContentCreationException
)
130 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
131 m_pProvider( pProvider
),
132 m_bTransient( sal_True
)
134 CLEAR_INFO (&m_info
);
136 #if OSL_DEBUG_LEVEL > 1
137 g_warning ("New Transient content ('%s') (%d)", getURI(), IsFolder
);
139 // m_info.name = FIXME: set name ?
140 m_info
.valid_fields
= GNOME_VFS_FILE_INFO_FIELDS_TYPE
;
141 m_info
.type
= IsFolder
? GNOME_VFS_FILE_TYPE_DIRECTORY
:
142 GNOME_VFS_FILE_TYPE_REGULAR
;
148 gnome_vfs_file_info_clear( &m_info
);
152 // XInterface methods.
155 void SAL_CALL
Content::acquire()
158 ContentImplHelper::acquire();
160 void SAL_CALL
Content::release()
163 ContentImplHelper::release();
165 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
166 throw ( uno::RuntimeException
)
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
>() )
176 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
180 // XTypeProvider methods.
183 XTYPEPROVIDER_COMMON_IMPL( Content
);
185 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
186 throw( uno::RuntimeException
)
188 static cppu::OTypeCollection
*pFolderCollection
= NULL
;
189 static cppu::OTypeCollection
*pFileCollection
= NULL
;
191 if (!pFolderCollection
) {
192 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
194 if (!pFolderCollection
) {
195 static cppu::OTypeCollection aFolderCollection
196 (CPPU_TYPE_REF( lang::XTypeProvider
),
197 CPPU_TYPE_REF( lang::XServiceInfo
),
198 CPPU_TYPE_REF( lang::XComponent
),
199 CPPU_TYPE_REF( ucb::XContent
),
200 CPPU_TYPE_REF( ucb::XCommandProcessor
),
201 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
202 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
203 CPPU_TYPE_REF( beans::XPropertyContainer
),
204 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
205 CPPU_TYPE_REF( container::XChild
),
206 CPPU_TYPE_REF( ucb::XContentCreator
) ); // !!
207 static cppu::OTypeCollection aFileCollection
208 (CPPU_TYPE_REF( lang::XTypeProvider
),
209 CPPU_TYPE_REF( lang::XServiceInfo
),
210 CPPU_TYPE_REF( lang::XComponent
),
211 CPPU_TYPE_REF( ucb::XContent
),
212 CPPU_TYPE_REF( ucb::XCommandProcessor
),
213 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
214 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
215 CPPU_TYPE_REF( beans::XPropertyContainer
),
216 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
217 CPPU_TYPE_REF( container::XChild
) );
219 pFolderCollection
= &aFolderCollection
;
220 pFileCollection
= &aFileCollection
;
221 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
225 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
228 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
229 return pFolderCollection
->getTypes();
231 return pFileCollection
->getTypes();
235 // XServiceInfo methods.
238 OUString SAL_CALL
Content::getImplementationName()
239 throw( uno::RuntimeException
)
241 return OUString("com.sun.star.comp.GnomeVFSContent");
244 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
245 throw( uno::RuntimeException
)
247 uno::Sequence
< OUString
> aSNS( 1 );
248 aSNS
.getArray()[ 0 ] = "com.sun.star.ucb.GnomeVFSContent";
256 OUString SAL_CALL
Content::getContentType()
257 throw( uno::RuntimeException
)
259 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
260 return OUString( GVFS_FOLDER_TYPE
);
262 return OUString( GVFS_FILE_TYPE
);
266 // XCommandProcessor methods.
269 uno::Any
Content::getBadArgExcept()
271 return uno::makeAny( lang::IllegalArgumentException
272 ( OUString("Wrong argument type!"),
273 static_cast< cppu::OWeakObject
* >( this ),
279 uno::Any SAL_CALL
Content::execute(
280 const ucb::Command
& aCommand
,
281 sal_Int32
/*CommandId*/,
282 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
283 throw( uno::Exception
,
284 ucb::CommandAbortedException
,
285 uno::RuntimeException
)
289 #if OSL_DEBUG_LEVEL > 1
291 uno::Reference
< task::XInteractionHandler
> xIH
;
294 xIH
= xEnv
->getInteractionHandler();
295 g_warning( "Execute command: '%s' with %s interaction env",
296 OUStringToGnome( aCommand
.Name
),
297 xIH
.is() ? "" : "NO" );
301 #define COMMAND_IS(cmd,name) ( (cmd).Name == name )
303 if ( COMMAND_IS( aCommand
, "getPropertyValues" ) ) {
304 uno::Sequence
< beans::Property
> Properties
;
306 if ( !( aCommand
.Argument
>>= Properties
) )
307 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
309 aRet
<<= getPropertyValues( Properties
, xEnv
);
311 } else if ( COMMAND_IS( aCommand
, "setPropertyValues" ) ) {
312 uno::Sequence
< beans::PropertyValue
> aProperties
;
314 if ( !( aCommand
.Argument
>>= aProperties
) ||
315 !aProperties
.getLength() )
316 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
318 aRet
<<= setPropertyValues( aProperties
, xEnv
);
320 } else if ( COMMAND_IS( aCommand
, "getPropertySetInfo" ) ) {
321 aRet
<<= getPropertySetInfo( xEnv
, sal_False
);
323 } else if ( COMMAND_IS( aCommand
, "getCommandInfo" ) ) {
324 aRet
<<= getCommandInfo( xEnv
, sal_False
);
326 } else if ( COMMAND_IS( aCommand
, "open" ) ) {
327 ucb::OpenCommandArgument2 aOpenCommand
;
328 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
329 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
331 sal_Bool bOpenFolder
=
332 ( ( aOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
333 ( aOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
334 ( aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
) );
336 if ( bOpenFolder
&& isFolder( xEnv
) ) {
337 uno::Reference
< ucb::XDynamicResultSet
> xSet
338 = new DynamicResultSet( m_xContext
, this, aOpenCommand
, xEnv
);
341 } else if ( aOpenCommand
.Sink
.is() ) {
343 if ( ( aOpenCommand
.Mode
344 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
346 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) ) {
347 ucbhelper::cancelCommandExecution
348 ( uno::makeAny ( ucb::UnsupportedOpenModeException
350 static_cast< cppu::OWeakObject
* >( this ),
351 sal_Int16( aOpenCommand
.Mode
) ) ),
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...
359 g_warning ("Failed to load data from '%s'", getURI());
361 ucbhelper::cancelCommandExecution
362 ( uno::makeAny (ucb::UnsupportedDataSinkException
364 static_cast< cppu::OWeakObject
* >( this ),
365 aOpenCommand
.Sink
) ),
371 g_warning ("Open falling through ...");
374 } else if ( COMMAND_IS( aCommand
, "createNewContent" ) && isFolder( xEnv
) ) {
375 ucb::ContentInfo arg
;
376 if ( !( aCommand
.Argument
>>= arg
) )
377 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
379 aRet
<<= createNewContent( arg
);
381 } else if ( COMMAND_IS( aCommand
, "insert" ) ) {
382 ucb::InsertCommandArgument arg
;
383 if ( !( aCommand
.Argument
>>= arg
) )
384 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
386 insert( arg
.Data
, arg
.ReplaceExisting
, xEnv
);
388 } else if ( COMMAND_IS( aCommand
, "delete" ) ) {
390 sal_Bool bDeletePhysical
= sal_False
;
391 aCommand
.Argument
>>= bDeletePhysical
;
393 OString aURI
= getOURI();
394 GnomeVFSResult result
= gnome_vfs_unlink (aURI
.getStr());
396 if (result
!= GNOME_VFS_OK
)
397 cancelCommandExecution( result
, xEnv
, sal_True
);
399 destroy( bDeletePhysical
);
401 } else if ( COMMAND_IS( aCommand
, "transfer" ) && isFolder( xEnv
) ) {
402 ucb::TransferInfo transferArgs
;
404 if ( !( aCommand
.Argument
>>= transferArgs
) )
405 ucbhelper::cancelCommandExecution( getBadArgExcept(), xEnv
);
407 transfer( transferArgs
, xEnv
);
409 } else { // Unsuported
411 g_warning( "Unsupported command: '%s'",
412 OUStringToGnome( aCommand
.Name
) );
414 ucbhelper::cancelCommandExecution
415 ( uno::makeAny( ucb::UnsupportedCommandException
417 static_cast< cppu::OWeakObject
* >( this ) ) ),
425 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
426 throw( uno::RuntimeException
)
428 // FIXME: we should use the GnomeVFSCancellation APIs here ...
432 // XContentCreator methods.
435 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
436 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
437 throw( uno::RuntimeException
)
439 if ( isFolder( xEnv
) )
441 uno::Sequence
< ucb::ContentInfo
> seq(2);
443 // Minimum set of props we really need
444 uno::Sequence
< beans::Property
> props( 1 );
445 props
[0] = beans::Property(
448 getCppuType( static_cast< OUString
* >( 0 ) ),
449 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
);
452 seq
[0].Type
= OUString( GVFS_FILE_TYPE
);
453 seq
[0].Attributes
= ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
454 ucb::ContentInfoAttribute::KIND_DOCUMENT
);
455 seq
[0].Properties
= props
;
458 seq
[1].Type
= OUString( GVFS_FOLDER_TYPE
);
459 seq
[1].Attributes
= ucb::ContentInfoAttribute::KIND_FOLDER
;
460 seq
[1].Properties
= props
;
466 return uno::Sequence
< ucb::ContentInfo
>();
470 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
471 throw( uno::RuntimeException
)
473 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
476 uno::Reference
< ucb::XContent
> SAL_CALL
477 Content::createNewContent( const ucb::ContentInfo
& Info
)
478 throw( uno::RuntimeException
)
480 bool create_document
;
483 if ( Info
.Type
== GVFS_FILE_TYPE
)
484 create_document
= true;
485 else if ( Info
.Type
== GVFS_FOLDER_TYPE
)
486 create_document
= false;
489 g_warning( "Failed to create new content '%s'",
490 OUStringToGnome( Info
.Type
) );
492 return uno::Reference
< ucb::XContent
>();
495 #if OSL_DEBUG_LEVEL > 1
496 g_warning( "createNewContent (%d)", (int) create_document
);
499 OUString aURL
= getOUURI();
501 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
504 name
= create_document
? "[New_Content]" : "[New_Collection]";
505 // This looks problematic to me cf. webdav
506 aURL
+= OUString::createFromAscii( name
);
508 uno::Reference
< ucb::XContentIdentifier
> xId
509 ( new ::ucbhelper::ContentIdentifier( aURL
) );
512 return new ::gvfs::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
513 } catch ( ucb::ContentCreationException
& ) {
514 return uno::Reference
< ucb::XContent
>();
518 OUString
Content::getParentURL()
522 // <scheme>://foo -> ""
523 // <scheme>://foo/ -> ""
524 // <scheme>://foo/bar -> <scheme>://foo/
525 // <scheme>://foo/bar/ -> <scheme>://foo/
526 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
528 OUString aURL
= getOUURI();
530 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
531 if ( nPos
== ( aURL
.getLength() - 1 ) ) {
532 // Trailing slash found. Skip.
533 nPos
= aURL
.lastIndexOf( '/', nPos
);
536 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
538 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
541 aParentURL
= aURL
.copy( 0, nPos
+ 1 );
543 #if OSL_DEBUG_LEVEL > 1
544 g_warning ("getParentURL '%s' -> '%s'",
545 getURI(), OUStringToOString
546 ( aParentURL
, RTL_TEXTENCODING_UTF8
).getStr() );
552 static util::DateTime
553 getDateFromUnix (time_t t
)
560 if ( osl_getDateTimeFromTimeValue( &tv
, &dt
) )
561 return util::DateTime( 0, dt
.Seconds
, dt
.Minutes
, dt
.Hours
,
562 dt
.Day
, dt
.Month
, dt
.Year
, false);
564 return util::DateTime();
567 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
568 const uno::Sequence
< beans::Property
>& rProperties
,
569 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
572 uno::Sequence
< beans::Property
> allProperties
;
576 const beans::Property
* pProps
;
578 if( rProperties
.getLength() ) {
579 nProps
= rProperties
.getLength();
580 pProps
= rProperties
.getConstArray();
582 allProperties
= getPropertySetInfo( xEnv
)->getProperties();
583 nProps
= allProperties
.getLength();
584 pProps
= allProperties
.getConstArray();
587 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
588 = new ::ucbhelper::PropertyValueSet( m_xContext
);
590 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
591 for( sal_Int32 n
= 0; n
< nProps
; ++n
) {
592 const beans::Property
& rProp
= pProps
[ n
];
594 if ( rProp
.Name
== "Title" ) {
596 if (m_info
.name
[0] == '/')
597 g_warning ("Odd NFS title on item '%s' == '%s'",
598 getURI(), m_info
.name
);
599 xRow
->appendString( rProp
, GnomeToOUString( m_info
.name
) );
601 xRow
->appendVoid( rProp
);
604 else if ( rProp
.Name
== "ContentType" )
605 xRow
->appendString( rProp
, getContentType () );
607 else if ( rProp
.Name
== "IsDocument" ) {
608 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
609 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_REGULAR
||
610 m_info
.type
== GNOME_VFS_FILE_TYPE_UNKNOWN
) );
612 xRow
->appendVoid( rProp
);
614 else if ( rProp
.Name
== "IsFolder" ) {
615 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
616 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) );
618 xRow
->appendVoid( rProp
);
620 else if ( rProp
.Name
== "IsReadOnly" ) {
622 GnomeVFSFileInfo
* fileInfo
= gnome_vfs_file_info_new ();
624 OString aURI
= getOURI();
625 gnome_vfs_get_file_info
626 ( aURI
.getStr(), fileInfo
,
627 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
);
629 if (fileInfo
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_ACCESS
) {
630 bool read_only
= true;
632 if (fileInfo
->permissions
& GNOME_VFS_PERM_ACCESS_WRITABLE
)
635 xRow
->appendBoolean( rProp
, read_only
);
637 xRow
->appendVoid( rProp
);
638 gnome_vfs_file_info_unref (fileInfo
);
640 else if ( rProp
.Name
== "Size" ) {
641 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
)
642 xRow
->appendLong( rProp
, m_info
.size
);
644 xRow
->appendVoid( rProp
);
646 else if ( rProp
.Name
== "IsHidden" )
648 xRow
->appendBoolean( rProp
, m_info
.name
[0] == '.' );
650 xRow
->appendVoid( rProp
);
652 else if ( rProp
.Name
== "IsVolume" || rProp
.Name
== "IsCompactDisk" )
653 xRow
->appendBoolean( rProp
, sal_False
);
655 else if ( rProp
.Name
== "DateCreated" ) {
656 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_CTIME
)
657 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.ctime
) );
659 xRow
->appendVoid( rProp
);
662 else if ( rProp
.Name
== "DateModified" ) {
663 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
664 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.mtime
) );
666 xRow
->appendVoid( rProp
);
669 else if ( rProp
.Name
== "MediaType" ) {
670 // We do this by sniffing in gnome-vfs; rather expensively.
672 g_warning ("FIXME: Requested mime-type - an expensive op. indeed!");
674 xRow
->appendVoid( rProp
);
675 } else if ( rProp
.Name
== "CreatableContentsInfo" )
676 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
679 xRow
->appendVoid( rProp
);
682 #if OSL_DEBUG_LEVEL > 1
683 g_warning ("getPropertyValues on '%s' %d properties returned (of %d)",
684 getURI(), 0, (int)nProps
);
687 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
690 static lang::IllegalAccessException
691 getReadOnlyException( Content
*ctnt
)
693 return lang::IllegalAccessException
694 ( OUString("Property is read-only!"),
695 static_cast< cppu::OWeakObject
* >( ctnt
) );
699 Content::makeNewURL( const char */
*newName*/
)
701 OUString aNewURL
= getParentURL();
702 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
705 char *name
= gnome_vfs_escape_string( m_info
.name
);
706 aNewURL
+= GnomeToOUString( name
);
712 // This is slightly complicated by needing to support either 'move' or 'setname'
714 Content::doSetFileInfo( const GnomeVFSFileInfo
*newInfo
,
715 GnomeVFSSetFileInfoMask setMask
,
716 const uno::Reference
< ucb::XCommandEnvironment
>& /*xEnv*/ )
718 GnomeVFSResult result
= GNOME_VFS_OK
;
720 g_assert (!m_bTransient
);
722 OString aURI
= getOURI();
724 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
726 // The simple approach:
727 if( setMask
!= GNOME_VFS_SET_FILE_INFO_NONE
)
728 result
= gnome_vfs_set_file_info
// missed a const in the API there
729 ( aURI
.getStr(), (GnomeVFSFileInfo
*)newInfo
, setMask
);
731 if ( result
== GNOME_VFS_ERROR_NOT_SUPPORTED
&&
732 ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) ) {
733 // Try a move instead
735 g_warning( "SetFileInfo not supported on '%s'", getURI() );
738 char *newURI
= OUStringToGnome( makeNewURL( newInfo
->name
) );
740 result
= gnome_vfs_move (aURI
.getStr(), newURI
, FALSE
);
749 uno::Sequence
< uno::Any
> Content::setPropertyValues(
750 const uno::Sequence
< beans::PropertyValue
>& rValues
,
751 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
754 GnomeVFSFileInfo newInfo
;
755 int setMask
= GNOME_VFS_SET_FILE_INFO_NONE
;
759 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
761 gnome_vfs_file_info_copy( &newInfo
, &m_info
);
763 Authentication
aAuth( xEnv
);
765 int nChanged
= 0, nTitlePos
= 0;
766 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
767 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
769 beans::PropertyChangeEvent aEvent
;
770 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
771 aEvent
.Further
= sal_False
;
772 aEvent
.PropertyHandle
= -1;
773 // aEvent.PropertyName = fill in later ...
777 int nCount
= rValues
.getLength();
778 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
780 for ( sal_Int32 n
= 0; n
< nCount
; ++n
) {
781 const beans::PropertyValue
& rValue
= pValues
[ n
];
783 #if OSL_DEBUG_LEVEL > 1
784 g_warning( "Set prop '%s'", OUStringToGnome( rValue
.Name
) );
786 if ( rValue
.Name
== "ContentType" ||
787 rValue
.Name
== "MediaType" ||
788 rValue
.Name
== "IsDocument" ||
789 rValue
.Name
== "IsFolder" ||
790 rValue
.Name
== "Size" ||
791 rValue
.Name
== "CreatableContentsInfo" )
792 aRet
[ n
] <<= getReadOnlyException( this );
794 else if ( rValue
.Name
== "Title" ) {
795 if ( rValue
.Value
>>= aNewTitle
) {
796 if ( aNewTitle
.isEmpty() )
797 aRet
[ n
] <<= lang::IllegalArgumentException
798 ( OUString("Empty title not allowed!"),
799 static_cast< cppu::OWeakObject
* >( this ), -1 );
801 char *newName
= OUStringToGnome( aNewTitle
);
803 if( !newName
|| !m_info
.name
|| strcmp( newName
, m_info
.name
) ) {
804 #if OSL_DEBUG_LEVEL > 1
805 g_warning ("Set new name to '%s'", newName
);
808 aEvent
.PropertyName
= "Title";
809 aEvent
.OldValue
= uno::makeAny( GnomeToOUString( newInfo
.name
) );
810 aEvent
.NewValue
= uno::makeAny( aNewTitle
);
811 aChanges
.getArray()[ nChanged
] = aEvent
;
812 nTitlePos
= nChanged
++;
814 newInfo
.name
= newName
;
815 setMask
|= GNOME_VFS_SET_FILE_INFO_NAME
;
820 aRet
[ n
] <<= beans::IllegalTypeException
821 ( OUString("Property value has wrong type!"),
822 static_cast< cppu::OWeakObject
* >( this ) );
824 } else if ( rValue
.Name
== "DateCreated" || rValue
.Name
== "DateModified" ) {
825 // FIXME: should be able to set the timestamps
826 aRet
[ n
] <<= getReadOnlyException( this );
829 g_warning( "Unhandled property '%s'", OUStringToGnome( rValue
.Name
) );
831 aRet
[ n
] <<= getReadOnlyException( this );
835 GnomeVFSResult result
= GNOME_VFS_OK
;
837 if ( !m_bTransient
&&
838 ( result
= doSetFileInfo( &newInfo
,
839 (GnomeVFSSetFileInfoMask
) setMask
,
840 xEnv
) ) != GNOME_VFS_OK
) {
841 for (int i
= 0; i
< nChanged
; i
++)
842 aRet
[ i
] <<= mapVFSException( result
, sal_True
);
846 if ( result
== GNOME_VFS_OK
) {
847 gnome_vfs_file_info_copy( &m_info
, &newInfo
);
849 if ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) {
850 uno::Reference
< ucb::XContentIdentifier
> xNewId
851 = new ::ucbhelper::ContentIdentifier( makeNewURL( newInfo
.name
) );
854 if (!exchangeIdentity( xNewId
) )
855 aRet
[ nTitlePos
] <<= uno::Exception
856 ( OUString("Exchange failed!"),
857 static_cast< cppu::OWeakObject
* >( this ) );
861 gnome_vfs_file_info_clear( &newInfo
);
863 if ( nChanged
> 0 ) {
865 aChanges
.realloc( nChanged
);
866 notifyPropertiesChange( aChanges
);
872 void Content::queryChildren( ContentRefList
& rChildren
)
874 // Obtain a list with a snapshot of all currently instanciated contents
875 // from provider and extract the contents which are direct children
878 ::ucbhelper::ContentRefList aAllContents
;
879 m_xProvider
->queryExistingContents( aAllContents
);
881 OUString aURL
= getOUURI();
882 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
884 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
887 sal_Int32 nLen
= aURL
.getLength();
889 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
890 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
892 while ( it
!= end
) {
893 ::ucbhelper::ContentImplHelperRef xChild
= (*it
);
895 = xChild
->getIdentifier()->getContentIdentifier();
897 // Is aURL a prefix of aChildURL?
898 if ( ( aChildURL
.getLength() > nLen
) &&
899 ( aChildURL
.compareTo( aURL
, nLen
) == 0 ) ) {
900 sal_Int32 nPos
= nLen
;
901 nPos
= aChildURL
.indexOf( '/', nPos
);
903 if ( ( nPos
== -1 ) ||
904 ( nPos
== ( aChildURL
.getLength() - 1 ) ) ) {
905 // No further slashes / only a final slash. It's a child!
906 rChildren
.push_back( ::gvfs::Content::ContentRef
907 (static_cast< ::gvfs::Content
* >(xChild
.get() ) ) );
914 void Content::insert(
915 const uno::Reference
< io::XInputStream
> &xInputStream
,
916 sal_Bool bReplaceExisting
,
917 const uno::Reference
< ucb::XCommandEnvironment
> &xEnv
)
918 throw( uno::Exception
)
920 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
922 #if OSL_DEBUG_LEVEL > 1
923 g_warning( "Insert '%s' (%d) (0x%x:%d)", getURI(), bReplaceExisting
,
924 m_info
.valid_fields
, m_info
.type
);
927 GnomeVFSResult result
= getInfo( xEnv
);
928 // a racy design indeed.
929 if( !bReplaceExisting
&& !m_bTransient
&&
930 result
!= GNOME_VFS_ERROR_NOT_FOUND
) {
932 g_warning ("Nasty error inserting to '%s' ('%s')",
933 getURI(), gnome_vfs_result_to_string( result
));
935 cancelCommandExecution( GNOME_VFS_ERROR_FILE_EXISTS
, xEnv
, sal_True
);
938 if ( m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
939 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) {
940 OString aURI
= getOURI();
943 perm
= ( GNOME_VFS_PERM_USER_ALL
|
944 GNOME_VFS_PERM_GROUP_READ
|
945 GNOME_VFS_PERM_OTHER_READ
);
947 #if OSL_DEBUG_LEVEL > 1
948 g_warning ("Make directory");
950 result
= gnome_vfs_make_directory( aURI
.getStr(), perm
);
952 if( result
!= GNOME_VFS_OK
)
953 cancelCommandExecution( result
, xEnv
, sal_True
);
958 if ( !xInputStream
.is() ) {
959 // FIXME: slightly unclear whether to accept this and create an empty file
960 ucbhelper::cancelCommandExecution
962 ( ucb::MissingInputStreamException
964 static_cast< cppu::OWeakObject
* >( this ) ) ),
968 GnomeVFSHandle
*handle
= NULL
;
969 OString aURI
= getOURI();
971 result
= GNOME_VFS_ERROR_GENERIC
;
972 if ( bReplaceExisting
) {
973 Authentication
aAuth( xEnv
);
974 result
= gnome_vfs_open( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
);
977 if ( result
!= GNOME_VFS_OK
) {
979 Authentication
aAuth( xEnv
);
981 perm
= ( ( GNOME_VFS_PERM_USER_WRITE
| GNOME_VFS_PERM_USER_READ
) |
982 ( GNOME_VFS_PERM_GROUP_WRITE
| GNOME_VFS_PERM_GROUP_READ
) );
984 result
= gnome_vfs_create
985 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
, TRUE
, perm
);
988 if( result
!= GNOME_VFS_OK
)
989 cancelCommandExecution( result
, xEnv
, sal_True
);
991 if ( !xInputStream
.is() ) {
992 result
= gnome_vfs_close( handle
);
993 if (result
!= GNOME_VFS_OK
)
994 cancelCommandExecution( result
, xEnv
, sal_True
);
996 } else { // copy it over
997 uno::Reference
< io::XOutputStream
> xOutput
=
998 new gvfs::Stream( handle
, &m_info
);
1000 copyData( xInputStream
, xOutput
);
1004 m_bTransient
= sal_False
;
1010 void Content::transfer(const ucb::TransferInfo
& /*rArgs*/,
1011 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1012 throw( uno::Exception
)
1014 // FIXME: see gnome-vfs-xfer.h - but we need to be able to easily
1015 // detect which are gnome-vfs owned URI types ...
1016 ucbhelper::cancelCommandExecution
1018 ( ucb::InteractiveBadTransferURLException
1019 ( OUString("Unsupported URL scheme!"),
1020 static_cast< cppu::OWeakObject
* >( this ) ) ),
1024 void Content::destroy( sal_Bool bDeletePhysical
)
1025 throw( uno::Exception
)
1027 // @@@ take care about bDeletePhysical -> trashcan support
1028 uno::Reference
< ucb::XContent
> xThis
= this;
1032 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1034 // Process instanciated children...
1035 ::gvfs::Content::ContentRefList aChildren
;
1036 queryChildren( aChildren
);
1038 ContentRefList::const_iterator it
= aChildren
.begin();
1039 ContentRefList::const_iterator end
= aChildren
.end();
1041 while ( it
!= end
) {
1042 (*it
)->destroy( bDeletePhysical
);
1047 // Used by the 'setPropertyValues' method for
1048 // propagating the renaming of a Content.
1049 sal_Bool
Content::exchangeIdentity(
1050 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1055 uno::Reference
< ucb::XContent
> xThis
= this;
1057 #if OSL_DEBUG_LEVEL > 1
1058 g_warning( "exchangeIdentity from '%s' to '%s'",
1059 getURI(), OUStringToGnome( xNewId
->getContentIdentifier() ) );
1062 if ( m_bTransient
) {
1063 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1064 /* FIXME: can we not screw up an identically named
1065 * Content pointing to ourself here ? */
1066 m_xIdentifier
= xNewId
;
1070 OUString aOldURL
= getOUURI();
1072 // Exchange own identitity.
1073 if ( exchange( xNewId
) ) {
1075 // Process instanciated children...
1076 ContentRefList aChildren
;
1077 queryChildren( aChildren
);
1079 ContentRefList::const_iterator it
= aChildren
.begin();
1080 ContentRefList::const_iterator end
= aChildren
.end();
1082 while ( it
!= end
) {
1083 ContentRef xChild
= (*it
);
1085 // Create new content identifier for the child...
1086 uno::Reference
< ucb::XContentIdentifier
>
1087 xOldChildId
= xChild
->getIdentifier();
1088 OUString aOldChildURL
1089 = xOldChildId
->getContentIdentifier();
1090 OUString aNewChildURL
1091 = aOldChildURL
.replaceAt(
1093 aOldURL
.getLength(),
1094 xNewId
->getContentIdentifier() );
1095 uno::Reference
< ucb::XContentIdentifier
>
1097 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1099 if ( !xChild
->exchangeIdentity( xNewChildId
) )
1111 Content::getInfo( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1113 GnomeVFSResult result
;
1114 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1117 result
= GNOME_VFS_OK
;
1119 else if ( !m_info
.valid_fields
) {
1120 OString aURI
= getOURI();
1121 Authentication
aAuth( xEnv
);
1122 result
= gnome_vfs_get_file_info
1123 ( aURI
.getStr(), &m_info
, GNOME_VFS_FILE_INFO_DEFAULT
);
1124 if (result
!= GNOME_VFS_OK
)
1128 "gnome_vfs_get_file_info for <" << aURI
<< "> failed with \""
1129 << gnome_vfs_result_to_string(result
) << "\" (" << +result
1131 gnome_vfs_file_info_clear( &m_info
);
1134 result
= GNOME_VFS_OK
;
1135 #if OSL_DEBUG_LEVEL > 1
1136 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)",
1137 getURI(), gnome_vfs_result_to_string( result
),
1138 result
, m_info
.valid_fields
);
1144 Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1146 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1148 return (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
1149 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
);
1152 uno::Any
Content::mapVFSException( const GnomeVFSResult result
, sal_Bool bWrite
)
1154 uno::Any aException
;
1155 const char *gvfs_message
;
1157 uno::Sequence
< uno::Any
> aArgs( 1 );
1159 #if OSL_DEBUG_LEVEL > 1
1160 g_warning ("Map VFS exception '%s' (%d)",
1161 gnome_vfs_result_to_string( result
), result
);
1164 if ((gvfs_message
= gnome_vfs_result_to_string (result
)))
1165 message
= GnomeToOUString( gvfs_message
);
1169 g_warning("VFS_OK mapped to exception.");
1171 case GNOME_VFS_ERROR_EOF
:
1172 g_warning ("VFS_EOF not handled somewhere.");
1174 case GNOME_VFS_ERROR_NOT_FOUND
:
1175 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
1177 ucb::InteractiveAugmentedIOException
1178 ( OUString("Not found!"),
1179 static_cast< cppu::OWeakObject
* >( this ),
1180 task::InteractionClassification_ERROR
,
1181 ucb::IOErrorCode_NOT_EXISTING
,
1184 case GNOME_VFS_ERROR_BAD_PARAMETERS
:
1186 lang::IllegalArgumentException
1188 static_cast< cppu::OWeakObject
* >( this ),
1191 case GNOME_VFS_ERROR_GENERIC
:
1192 case GNOME_VFS_ERROR_INTERNAL
:
1193 case GNOME_VFS_ERROR_NOT_SUPPORTED
:
1195 g_warning ("Internal - un-mapped error");
1197 aException
<<= io::IOException();
1199 case GNOME_VFS_ERROR_IO
:
1202 ucb::InteractiveNetworkWriteException
1204 static_cast< cppu::OWeakObject
* >( this ),
1205 task::InteractionClassification_ERROR
,
1209 ucb::InteractiveNetworkReadException
1211 static_cast< cppu::OWeakObject
* >( this ),
1212 task::InteractionClassification_ERROR
,
1215 case GNOME_VFS_ERROR_HOST_NOT_FOUND
:
1216 case GNOME_VFS_ERROR_INVALID_HOST_NAME
:
1218 ucb::InteractiveNetworkResolveNameException
1220 static_cast< cppu::OWeakObject
* >( this ),
1221 task::InteractionClassification_ERROR
,
1224 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
:
1225 case GNOME_VFS_ERROR_SERVICE_OBSOLETE
:
1226 case GNOME_VFS_ERROR_PROTOCOL_ERROR
:
1227 case GNOME_VFS_ERROR_NO_MASTER_BROWSER
:
1229 ucb::InteractiveNetworkConnectException
1231 static_cast< cppu::OWeakObject
* >( this ),
1232 task::InteractionClassification_ERROR
,
1236 case GNOME_VFS_ERROR_FILE_EXISTS
:
1237 aException
<<= ucb::NameClashException
1239 static_cast< cppu::OWeakObject
* >( this ),
1240 task::InteractionClassification_ERROR
,
1244 case GNOME_VFS_ERROR_INVALID_OPEN_MODE
:
1245 aException
<<= ucb::UnsupportedOpenModeException();
1248 case GNOME_VFS_ERROR_CORRUPTED_DATA
:
1249 case GNOME_VFS_ERROR_WRONG_FORMAT
:
1250 case GNOME_VFS_ERROR_BAD_FILE
:
1251 case GNOME_VFS_ERROR_TOO_BIG
:
1252 case GNOME_VFS_ERROR_NO_SPACE
:
1253 case GNOME_VFS_ERROR_READ_ONLY
:
1254 case GNOME_VFS_ERROR_INVALID_URI
:
1255 case GNOME_VFS_ERROR_NOT_OPEN
:
1256 case GNOME_VFS_ERROR_ACCESS_DENIED
:
1257 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES
:
1258 case GNOME_VFS_ERROR_NOT_A_DIRECTORY
:
1259 case GNOME_VFS_ERROR_IN_PROGRESS
:
1260 case GNOME_VFS_ERROR_INTERRUPTED
:
1261 case GNOME_VFS_ERROR_LOOP
:
1262 case GNOME_VFS_ERROR_NOT_PERMITTED
:
1263 case GNOME_VFS_ERROR_IS_DIRECTORY
:
1264 case GNOME_VFS_ERROR_NO_MEMORY
:
1265 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS
:
1266 case GNOME_VFS_ERROR_LOGIN_FAILED
:
1267 case GNOME_VFS_ERROR_CANCELLED
:
1268 case GNOME_VFS_ERROR_DIRECTORY_BUSY
:
1269 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY
:
1270 case GNOME_VFS_ERROR_TOO_MANY_LINKS
:
1271 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM
:
1272 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM
:
1273 case GNOME_VFS_ERROR_NAME_TOO_LONG
:
1275 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)",
1276 gnome_vfs_result_to_string( result
), result
);
1279 aException
<<= ucb::InteractiveNetworkGeneralException
1281 static_cast< cppu::OWeakObject
* >( this ),
1282 task::InteractionClassification_ERROR
);
1289 void Content::cancelCommandExecution(
1290 GnomeVFSResult result
,
1291 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1292 sal_Bool bWrite
/* = sal_False */ )
1293 throw ( uno::Exception
)
1295 ucbhelper::cancelCommandExecution( mapVFSException( result
, bWrite
), xEnv
);
1299 uno::Sequence
< beans::Property
> Content::getProperties(
1300 const uno::Reference
< ucb::XCommandEnvironment
> & /*xEnv*/ )
1302 static const beans::Property aGenericProperties
[] = {
1303 beans::Property( OUString( "ContentType" ),
1304 -1, getCppuType( static_cast< const OUString
* >( 0 ) ),
1305 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1306 beans::Property( OUString( "IsDocument" ),
1307 -1, getCppuBooleanType(),
1308 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1309 beans::Property( OUString( "IsFolder" ),
1310 -1, getCppuBooleanType(),
1311 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1312 beans::Property( OUString( "Title" ),
1313 -1, getCppuType( static_cast< const OUString
* >( 0 ) ),
1314 beans::PropertyAttribute::BOUND
),
1316 beans::Property( OUString( "DateCreated" ),
1317 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1318 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1319 beans::Property( OUString( "DateModified" ),
1320 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1321 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1322 // FIXME: Too expensive for now (?)
1323 // beans::Property( OUString( "MediaType" ),
1324 // -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1325 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1326 beans::Property( OUString( "Size" ),
1327 -1, getCppuType( static_cast< const sal_Int64
* >( 0 ) ),
1328 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1329 beans::Property( OUString( "IsReadOnly" ),
1330 -1, getCppuBooleanType(),
1331 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1332 beans::Property( OUString( "IsVolume" ),
1333 -1, getCppuBooleanType(),
1334 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1335 beans::Property( OUString( "IsCompactDisk" ),
1336 -1, getCppuBooleanType(),
1337 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1338 beans::Property( OUString( "IsHidden" ),
1339 -1, getCppuBooleanType(),
1340 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1341 beans::Property( OUString( "CreatableContentsInfo" ),
1342 -1, getCppuType( static_cast< const uno::Sequence
< ucb::ContentInfo
> * >( 0 ) ),
1343 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
)
1346 const int nProps
= sizeof (aGenericProperties
) / sizeof (aGenericProperties
[0]);
1348 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1352 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1353 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1355 static const ucb::CommandInfo aCommandInfoTable
[] = {
1356 // Required commands
1358 ( OUString( "getCommandInfo" ),
1359 -1, getCppuVoidType() ),
1361 ( OUString( "getPropertySetInfo" ),
1362 -1, getCppuVoidType() ),
1364 ( OUString( "getPropertyValues" ),
1365 -1, getCppuType( static_cast<uno::Sequence
< beans::Property
> * >( 0 ) ) ),
1367 ( OUString( "setPropertyValues" ),
1368 -1, getCppuType( static_cast<uno::Sequence
< beans::PropertyValue
> * >( 0 ) ) ),
1370 // Optional standard commands
1372 ( OUString( "delete" ),
1373 -1, getCppuBooleanType() ),
1375 ( OUString( "insert" ),
1376 -1, getCppuType( static_cast<ucb::InsertCommandArgument
* >( 0 ) ) ),
1378 ( OUString( "open" ),
1379 -1, getCppuType( static_cast<ucb::OpenCommandArgument2
* >( 0 ) ) ),
1381 // Folder Only, omitted if not a folder
1383 ( OUString( "transfer" ),
1384 -1, getCppuType( static_cast<ucb::TransferInfo
* >( 0 ) ) ),
1386 ( OUString( "createNewContent" ),
1387 -1, getCppuType( static_cast<ucb::ContentInfo
* >( 0 ) ) )
1391 = sizeof( aCommandInfoTable
) / sizeof( aCommandInfoTable
[ 0 ] );
1392 return uno::Sequence
< ucb::CommandInfo
>(
1393 aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2 );
1397 Content::getOUURI ()
1399 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1400 return m_xIdentifier
->getContentIdentifier();
1406 return OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8
);
1412 return OUStringToGnome( getOUURI() );
1416 Content::copyData( uno::Reference
< io::XInputStream
> xIn
,
1417 uno::Reference
< io::XOutputStream
> xOut
)
1419 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1421 g_return_if_fail( xIn
.is() && xOut
.is() );
1423 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1424 xOut
->writeBytes( theData
);
1426 xOut
->closeOutput();
1429 // Inherits an authentication context
1430 uno::Reference
< io::XInputStream
>
1431 Content::createTempStream(
1432 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1433 throw( uno::Exception
)
1435 GnomeVFSResult result
;
1436 GnomeVFSHandle
*handle
= NULL
;
1437 OString aURI
= getOURI();
1439 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1440 // Something badly wrong happened - can't seek => stream to a temporary file
1441 uno::Reference
< io::XOutputStream
> xTempOut
=
1442 uno::Reference
< io::XOutputStream
>
1443 ( io::TempFile::create( m_xContext
), uno::UNO_QUERY
);
1445 if ( !xTempOut
.is() )
1446 cancelCommandExecution( GNOME_VFS_ERROR_IO
, xEnv
);
1448 result
= gnome_vfs_open
1449 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_READ
);
1450 if (result
!= GNOME_VFS_OK
)
1451 cancelCommandExecution( result
, xEnv
);
1453 uno::Reference
< io::XInputStream
> pStream
= new ::gvfs::Stream( handle
, &m_info
);
1454 copyData( pStream
, xTempOut
);
1456 return uno::Reference
< io::XInputStream
> ( xTempOut
, uno::UNO_QUERY
);
1459 uno::Reference
< io::XInputStream
>
1460 Content::createInputStream(
1461 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1462 throw( uno::Exception
)
1464 GnomeVFSHandle
*handle
= NULL
;
1465 GnomeVFSResult result
;
1466 uno::Reference
<io::XInputStream
> xIn
;
1468 Authentication
aAuth( xEnv
);
1469 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1472 OString aURI
= getOURI();
1474 if ( !(m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
) )
1475 return createTempStream( xEnv
);
1477 result
= gnome_vfs_open
1478 ( &handle
, aURI
.getStr(),
1479 (GnomeVFSOpenMode
) (GNOME_VFS_OPEN_READ
| GNOME_VFS_OPEN_RANDOM
) );
1481 if (result
== GNOME_VFS_ERROR_INVALID_OPEN_MODE
||
1482 result
== GNOME_VFS_ERROR_NOT_SUPPORTED
)
1483 return createTempStream( xEnv
);
1485 if (result
!= GNOME_VFS_OK
)
1486 cancelCommandExecution( result
, xEnv
);
1488 // Try a seek just to make sure it's Random access: some lie.
1489 result
= gnome_vfs_seek( handle
, GNOME_VFS_SEEK_START
, 0);
1490 if (result
== GNOME_VFS_ERROR_NOT_SUPPORTED
) {
1491 gnome_vfs_close( handle
);
1492 return createTempStream( xEnv
);
1495 if (result
!= GNOME_VFS_OK
)
1496 cancelCommandExecution( result
, xEnv
);
1499 xIn
= new ::gvfs::Stream( handle
, &m_info
);
1505 Content::feedSink( uno::Reference
< uno::XInterface
> aSink
,
1506 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1511 uno::Reference
< io::XOutputStream
> xOut
1512 = uno::Reference
< io::XOutputStream
>(aSink
, uno::UNO_QUERY
);
1513 uno::Reference
< io::XActiveDataSink
> xDataSink
1514 = uno::Reference
< io::XActiveDataSink
>(aSink
, uno::UNO_QUERY
);
1516 if ( !xOut
.is() && !xDataSink
.is() )
1519 uno::Reference
< io::XInputStream
> xIn
= createInputStream( xEnv
);
1524 copyData( xIn
, xOut
);
1526 if ( xDataSink
.is() )
1527 xDataSink
->setInputStream( xIn
);
1534 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
1535 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)"
1539 vfs_authentication_callback (gconstpointer in_void
,
1543 gpointer callback_data
)
1545 task::XInteractionHandler
*xIH
;
1547 #if OSL_DEBUG_LEVEL > 1
1548 g_warning ("Full authentication callback (%p) ...", callback_data
);
1551 if( !( xIH
= (task::XInteractionHandler
*) callback_data
) )
1554 const GnomeVFSModuleCallbackFullAuthenticationIn
*in
=
1555 (const GnomeVFSModuleCallbackFullAuthenticationIn
*) in_void
;
1556 GnomeVFSModuleCallbackFullAuthenticationOut
*out
=
1557 (GnomeVFSModuleCallbackFullAuthenticationOut
*) out_void
;
1559 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1560 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn
) == in_size
&&
1561 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut
) == out_size
);
1563 #if OSL_DEBUG_LEVEL > 1
1564 # define NNIL(x) (x?x:"<Null>")
1565 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' "
1566 "port %d auth_t '%s' user '%s' domain '%s' "
1567 "def user '%s', def domain '%s'",
1568 (int) in
->flags
, NNIL(in
->uri
), NNIL(in
->protocol
),
1569 NNIL(in
->server
), NNIL(in
->object
),
1570 (int) in
->port
, NNIL(in
->authtype
), NNIL(in
->username
), NNIL(in
->domain
),
1571 NNIL(in
->default_user
), NNIL(in
->default_domain
));
1575 ucbhelper::SimpleAuthenticationRequest::EntityType
1576 eDomain
, eUserName
, ePassword
;
1577 OUString aHostName
, aDomain
, aUserName
, aPassword
;
1579 aHostName
= GnomeToOUString( in
->server
);
1581 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
)
1583 aDomain
= GnomeToOUString( in
->domain
);
1584 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
;
1585 if (aDomain
.isEmpty())
1586 aDomain
= GnomeToOUString( in
->default_domain
);
1588 else // no underlying capability to display realm otherwise
1589 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
;
1591 aUserName
= GnomeToOUString( in
->username
);
1592 if (aUserName
.isEmpty())
1593 aUserName
= GnomeToOUString( in
->default_user
);
1594 eUserName
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
) ?
1595 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1596 (!aUserName
.isEmpty() ?
1597 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
:
1598 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
);
1600 // No suggested password.
1601 ePassword
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
) ?
1602 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1603 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
;
1605 // Really, really bad things happen if we don't provide
1606 // the same user/password as was entered last time if
1607 // we failed to authenticate - infinite looping / flickering
1608 // madness etc. [ nice infrastructure ! ]
1609 static OUString aLastUserName
, aLastPassword
;
1610 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
)
1612 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1613 aUserName
= aLastUserName
;
1614 aPassword
= aLastPassword
;
1617 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
1618 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in
->uri
),
1619 aHostName
, eDomain
, aDomain
,
1620 eUserName
, aUserName
,
1621 ePassword
, aPassword
);
1623 xIH
->handle( xRequest
.get() );
1625 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
1626 = xRequest
->getSelection();
1628 if ( xSelection
.is() ) {
1629 // Handler handled the request.
1630 uno::Reference
< task::XInteractionAbort
> xAbort(xSelection
.get(), uno::UNO_QUERY
);
1631 if ( !xAbort
.is() ) {
1632 const rtl::Reference
<
1633 ucbhelper::InteractionSupplyAuthentication
> & xSupp
1634 = xRequest
->getAuthenticationSupplier();
1636 OUString aNewDomain
, aNewUserName
, aNewPassword
;
1638 aNewUserName
= xSupp
->getUserName();
1639 if ( !aNewUserName
.isEmpty() )
1640 aUserName
= aNewUserName
;
1641 aNewDomain
= xSupp
->getRealm();
1642 if ( !aNewDomain
.isEmpty() )
1643 aDomain
= aNewDomain
;
1644 aNewPassword
= xSupp
->getPassword();
1645 if ( !aNewPassword
.isEmpty() )
1646 aPassword
= aNewPassword
;
1649 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1650 aLastUserName
= aUserName
;
1651 aLastPassword
= aPassword
;
1654 out
->username
= OUStringToGnome( aUserName
);
1655 out
->domain
= OUStringToGnome( aDomain
);
1656 out
->password
= OUStringToGnome( aPassword
);
1657 out
->save_password
= xSupp
->getRememberPasswordMode();
1659 #if OSL_DEBUG_LEVEL > 1
1660 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password",
1661 out
->username
, out
->domain
, out
->password
,
1662 out
->save_password
? "save" : "don't save");
1666 out
->abort_auth
= TRUE
;
1669 out
->abort_auth
= TRUE
;
1673 vfs_authentication_old_callback (gconstpointer in_void
,
1677 gpointer callback_data
)
1680 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data
);
1682 const GnomeVFSModuleCallbackAuthenticationIn
*in
=
1683 (const GnomeVFSModuleCallbackAuthenticationIn
*) in_void
;
1684 GnomeVFSModuleCallbackAuthenticationOut
*out
=
1685 (GnomeVFSModuleCallbackAuthenticationOut
*) out_void
;
1687 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1688 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn
) == in_size
&&
1689 sizeof (GnomeVFSModuleCallbackAuthenticationOut
) == out_size
);
1691 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in
= {
1692 (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1693 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
|
1694 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
|
1695 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
),
1696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1697 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out
= { 0, 0, 0, 0, 0, 0, 0, 0 };
1699 // Map the old style input auth. data to the new style structure.
1700 if (in
->previous_attempt_failed
)
1701 mapped_in
.flags
= (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1703 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
);
1705 GnomeVFSURI
*pURI
= NULL
;
1706 // Urk - parse all this from the URL ...
1707 mapped_in
.uri
= in
->uri
;
1710 pURI
= gnome_vfs_uri_new( in
->uri
);
1711 mapped_in
.protocol
= (char *) gnome_vfs_uri_get_scheme (pURI
);
1712 mapped_in
.server
= (char *) gnome_vfs_uri_get_host_name (pURI
);
1713 mapped_in
.port
= gnome_vfs_uri_get_host_port (pURI
);
1714 mapped_in
.username
= (char *) gnome_vfs_uri_get_user_name (pURI
);
1716 mapped_in
.domain
= in
->realm
;
1717 mapped_in
.default_user
= mapped_in
.username
;
1718 mapped_in
.default_domain
= mapped_in
.domain
;
1720 vfs_authentication_callback ((gconstpointer
) &mapped_in
,
1722 (gpointer
) &mapped_out
,
1723 sizeof (mapped_out
),
1727 gnome_vfs_uri_unref (pURI
);
1729 // Map the new style auth. out data to the old style out structure.
1730 out
->username
= mapped_out
.username
;
1731 out
->password
= mapped_out
.password
;
1732 g_free (mapped_out
.domain
);
1733 g_free (mapped_out
.keyring
);
1738 auth_destroy (gpointer data
)
1740 task::XInteractionHandler
*xIH
;
1741 if( ( xIH
= ( task::XInteractionHandler
* )data
) )
1745 // This sucks, but gnome-vfs doesn't much like
1746 // repeated set / unsets - so we have to compensate.
1747 GPrivate
*auth_queue
= NULL
;
1749 void auth_queue_destroy( gpointer data
)
1752 GQueue
*vq
= (GQueue
*) data
;
1754 for (l
= vq
->head
; l
; l
= l
->next
)
1755 auth_destroy (l
->data
);
1761 refresh_auth( GQueue
*vq
)
1765 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
);
1766 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
);
1768 for (l
= vq
->head
; l
; l
= l
->next
) {
1770 gnome_vfs_module_callback_push
1771 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
,
1772 vfs_authentication_old_callback
, l
->data
, NULL
);
1773 gnome_vfs_module_callback_push
1774 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
,
1775 vfs_authentication_callback
, l
->data
, NULL
);
1781 gvfs::Authentication::Authentication(
1782 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1785 uno::Reference
< task::XInteractionHandler
> xIH
;
1788 xIH
= xEnv
->getInteractionHandler();
1793 if( !(vq
= (GQueue
*)g_private_get( auth_queue
) ) ) {
1795 g_private_set( auth_queue
, vq
);
1798 g_queue_push_head( vq
, (gpointer
) xIH
.get() );
1802 gvfs::Authentication::~Authentication()
1807 vq
= (GQueue
*)g_private_get( auth_queue
);
1809 data
= g_queue_pop_head( vq
);
1810 auth_destroy (data
);
1815 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */