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 ] = OUString( "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() )
502 aURL
+= OUString("/");
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
= OUString( 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 ) )
703 aNewURL
+= OUString("/");
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
= OUString("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 ) )
885 aURL
+= OUString("/");
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
)
1125 gnome_vfs_file_info_clear( &m_info
);
1127 result
= GNOME_VFS_OK
;
1128 #if OSL_DEBUG_LEVEL > 1
1129 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)",
1130 getURI(), gnome_vfs_result_to_string( result
),
1131 result
, m_info
.valid_fields
);
1137 Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1139 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1141 return (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
1142 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
);
1145 uno::Any
Content::mapVFSException( const GnomeVFSResult result
, sal_Bool bWrite
)
1147 uno::Any aException
;
1148 const char *gvfs_message
;
1150 uno::Sequence
< uno::Any
> aArgs( 1 );
1152 #if OSL_DEBUG_LEVEL > 1
1153 g_warning ("Map VFS exception '%s' (%d)",
1154 gnome_vfs_result_to_string( result
), result
);
1157 if ((gvfs_message
= gnome_vfs_result_to_string (result
)))
1158 message
= GnomeToOUString( gvfs_message
);
1162 g_warning("VFS_OK mapped to exception.");
1164 case GNOME_VFS_ERROR_EOF
:
1165 g_warning ("VFS_EOF not handled somewhere.");
1167 case GNOME_VFS_ERROR_NOT_FOUND
:
1168 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
1170 ucb::InteractiveAugmentedIOException
1171 ( OUString("Not found!"),
1172 static_cast< cppu::OWeakObject
* >( this ),
1173 task::InteractionClassification_ERROR
,
1174 ucb::IOErrorCode_NOT_EXISTING
,
1177 case GNOME_VFS_ERROR_BAD_PARAMETERS
:
1179 lang::IllegalArgumentException
1181 static_cast< cppu::OWeakObject
* >( this ),
1184 case GNOME_VFS_ERROR_GENERIC
:
1185 case GNOME_VFS_ERROR_INTERNAL
:
1186 case GNOME_VFS_ERROR_NOT_SUPPORTED
:
1188 g_warning ("Internal - un-mapped error");
1190 aException
<<= io::IOException();
1192 case GNOME_VFS_ERROR_IO
:
1195 ucb::InteractiveNetworkWriteException
1197 static_cast< cppu::OWeakObject
* >( this ),
1198 task::InteractionClassification_ERROR
,
1202 ucb::InteractiveNetworkReadException
1204 static_cast< cppu::OWeakObject
* >( this ),
1205 task::InteractionClassification_ERROR
,
1208 case GNOME_VFS_ERROR_HOST_NOT_FOUND
:
1209 case GNOME_VFS_ERROR_INVALID_HOST_NAME
:
1211 ucb::InteractiveNetworkResolveNameException
1213 static_cast< cppu::OWeakObject
* >( this ),
1214 task::InteractionClassification_ERROR
,
1217 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
:
1218 case GNOME_VFS_ERROR_SERVICE_OBSOLETE
:
1219 case GNOME_VFS_ERROR_PROTOCOL_ERROR
:
1220 case GNOME_VFS_ERROR_NO_MASTER_BROWSER
:
1222 ucb::InteractiveNetworkConnectException
1224 static_cast< cppu::OWeakObject
* >( this ),
1225 task::InteractionClassification_ERROR
,
1229 case GNOME_VFS_ERROR_FILE_EXISTS
:
1230 aException
<<= ucb::NameClashException
1232 static_cast< cppu::OWeakObject
* >( this ),
1233 task::InteractionClassification_ERROR
,
1237 case GNOME_VFS_ERROR_INVALID_OPEN_MODE
:
1238 aException
<<= ucb::UnsupportedOpenModeException();
1241 case GNOME_VFS_ERROR_CORRUPTED_DATA
:
1242 case GNOME_VFS_ERROR_WRONG_FORMAT
:
1243 case GNOME_VFS_ERROR_BAD_FILE
:
1244 case GNOME_VFS_ERROR_TOO_BIG
:
1245 case GNOME_VFS_ERROR_NO_SPACE
:
1246 case GNOME_VFS_ERROR_READ_ONLY
:
1247 case GNOME_VFS_ERROR_INVALID_URI
:
1248 case GNOME_VFS_ERROR_NOT_OPEN
:
1249 case GNOME_VFS_ERROR_ACCESS_DENIED
:
1250 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES
:
1251 case GNOME_VFS_ERROR_NOT_A_DIRECTORY
:
1252 case GNOME_VFS_ERROR_IN_PROGRESS
:
1253 case GNOME_VFS_ERROR_INTERRUPTED
:
1254 case GNOME_VFS_ERROR_LOOP
:
1255 case GNOME_VFS_ERROR_NOT_PERMITTED
:
1256 case GNOME_VFS_ERROR_IS_DIRECTORY
:
1257 case GNOME_VFS_ERROR_NO_MEMORY
:
1258 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS
:
1259 case GNOME_VFS_ERROR_LOGIN_FAILED
:
1260 case GNOME_VFS_ERROR_CANCELLED
:
1261 case GNOME_VFS_ERROR_DIRECTORY_BUSY
:
1262 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY
:
1263 case GNOME_VFS_ERROR_TOO_MANY_LINKS
:
1264 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM
:
1265 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM
:
1266 case GNOME_VFS_ERROR_NAME_TOO_LONG
:
1268 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)",
1269 gnome_vfs_result_to_string( result
), result
);
1272 aException
<<= ucb::InteractiveNetworkGeneralException
1274 static_cast< cppu::OWeakObject
* >( this ),
1275 task::InteractionClassification_ERROR
);
1282 void Content::cancelCommandExecution(
1283 GnomeVFSResult result
,
1284 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1285 sal_Bool bWrite
/* = sal_False */ )
1286 throw ( uno::Exception
)
1288 ucbhelper::cancelCommandExecution( mapVFSException( result
, bWrite
), xEnv
);
1292 uno::Sequence
< beans::Property
> Content::getProperties(
1293 const uno::Reference
< ucb::XCommandEnvironment
> & /*xEnv*/ )
1295 static const beans::Property aGenericProperties
[] = {
1296 beans::Property( OUString( "ContentType" ),
1297 -1, getCppuType( static_cast< const OUString
* >( 0 ) ),
1298 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1299 beans::Property( OUString( "IsDocument" ),
1300 -1, getCppuBooleanType(),
1301 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1302 beans::Property( OUString( "IsFolder" ),
1303 -1, getCppuBooleanType(),
1304 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1305 beans::Property( OUString( "Title" ),
1306 -1, getCppuType( static_cast< const OUString
* >( 0 ) ),
1307 beans::PropertyAttribute::BOUND
),
1309 beans::Property( OUString( "DateCreated" ),
1310 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1311 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1312 beans::Property( OUString( "DateModified" ),
1313 -1, getCppuType( static_cast< const util::DateTime
* >( 0 ) ),
1314 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1315 // FIXME: Too expensive for now (?)
1316 // beans::Property( OUString( "MediaType" ),
1317 // -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1318 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1319 beans::Property( OUString( "Size" ),
1320 -1, getCppuType( static_cast< const sal_Int64
* >( 0 ) ),
1321 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1322 beans::Property( OUString( "IsReadOnly" ),
1323 -1, getCppuBooleanType(),
1324 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1325 beans::Property( OUString( "IsVolume" ),
1326 -1, getCppuBooleanType(),
1327 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1328 beans::Property( OUString( "IsCompactDisk" ),
1329 -1, getCppuBooleanType(),
1330 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1331 beans::Property( OUString( "IsHidden" ),
1332 -1, getCppuBooleanType(),
1333 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1334 beans::Property( OUString( "CreatableContentsInfo" ),
1335 -1, getCppuType( static_cast< const uno::Sequence
< ucb::ContentInfo
> * >( 0 ) ),
1336 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
)
1339 const int nProps
= sizeof (aGenericProperties
) / sizeof (aGenericProperties
[0]);
1341 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1345 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1346 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1348 static ucb::CommandInfo aCommandInfoTable
[] = {
1349 // Required commands
1351 ( OUString( "getCommandInfo" ),
1352 -1, getCppuVoidType() ),
1354 ( OUString( "getPropertySetInfo" ),
1355 -1, getCppuVoidType() ),
1357 ( OUString( "getPropertyValues" ),
1358 -1, getCppuType( static_cast<uno::Sequence
< beans::Property
> * >( 0 ) ) ),
1360 ( OUString( "setPropertyValues" ),
1361 -1, getCppuType( static_cast<uno::Sequence
< beans::PropertyValue
> * >( 0 ) ) ),
1363 // Optional standard commands
1365 ( OUString( "delete" ),
1366 -1, getCppuBooleanType() ),
1368 ( OUString( "insert" ),
1369 -1, getCppuType( static_cast<ucb::InsertCommandArgument
* >( 0 ) ) ),
1371 ( OUString( "open" ),
1372 -1, getCppuType( static_cast<ucb::OpenCommandArgument2
* >( 0 ) ) ),
1374 // Folder Only, omitted if not a folder
1376 ( OUString( "transfer" ),
1377 -1, getCppuType( static_cast<ucb::TransferInfo
* >( 0 ) ) ),
1379 ( OUString( "createNewContent" ),
1380 -1, getCppuType( static_cast<ucb::ContentInfo
* >( 0 ) ) )
1384 = sizeof( aCommandInfoTable
) / sizeof( aCommandInfoTable
[ 0 ] );
1385 return uno::Sequence
< ucb::CommandInfo
>(
1386 aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2 );
1390 Content::getOUURI ()
1392 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1393 return m_xIdentifier
->getContentIdentifier();
1399 return OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8
);
1405 return OUStringToGnome( getOUURI() );
1409 Content::copyData( uno::Reference
< io::XInputStream
> xIn
,
1410 uno::Reference
< io::XOutputStream
> xOut
)
1412 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1414 g_return_if_fail( xIn
.is() && xOut
.is() );
1416 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1417 xOut
->writeBytes( theData
);
1419 xOut
->closeOutput();
1422 // Inherits an authentication context
1423 uno::Reference
< io::XInputStream
>
1424 Content::createTempStream(
1425 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1426 throw( uno::Exception
)
1428 GnomeVFSResult result
;
1429 GnomeVFSHandle
*handle
= NULL
;
1430 OString aURI
= getOURI();
1432 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1433 // Something badly wrong happened - can't seek => stream to a temporary file
1434 uno::Reference
< io::XOutputStream
> xTempOut
=
1435 uno::Reference
< io::XOutputStream
>
1436 ( io::TempFile::create( m_xContext
), uno::UNO_QUERY
);
1438 if ( !xTempOut
.is() )
1439 cancelCommandExecution( GNOME_VFS_ERROR_IO
, xEnv
);
1441 result
= gnome_vfs_open
1442 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_READ
);
1443 if (result
!= GNOME_VFS_OK
)
1444 cancelCommandExecution( result
, xEnv
);
1446 uno::Reference
< io::XInputStream
> pStream
= new ::gvfs::Stream( handle
, &m_info
);
1447 copyData( pStream
, xTempOut
);
1449 return uno::Reference
< io::XInputStream
> ( xTempOut
, uno::UNO_QUERY
);
1452 uno::Reference
< io::XInputStream
>
1453 Content::createInputStream(
1454 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1455 throw( uno::Exception
)
1457 GnomeVFSHandle
*handle
= NULL
;
1458 GnomeVFSResult result
;
1459 uno::Reference
<io::XInputStream
> xIn
;
1461 Authentication
aAuth( xEnv
);
1462 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1465 OString aURI
= getOURI();
1467 if ( !(m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
) )
1468 return createTempStream( xEnv
);
1470 result
= gnome_vfs_open
1471 ( &handle
, aURI
.getStr(),
1472 (GnomeVFSOpenMode
) (GNOME_VFS_OPEN_READ
| GNOME_VFS_OPEN_RANDOM
) );
1474 if (result
== GNOME_VFS_ERROR_INVALID_OPEN_MODE
||
1475 result
== GNOME_VFS_ERROR_NOT_SUPPORTED
)
1476 return createTempStream( xEnv
);
1478 if (result
!= GNOME_VFS_OK
)
1479 cancelCommandExecution( result
, xEnv
);
1481 // Try a seek just to make sure it's Random access: some lie.
1482 result
= gnome_vfs_seek( handle
, GNOME_VFS_SEEK_START
, 0);
1483 if (result
== GNOME_VFS_ERROR_NOT_SUPPORTED
) {
1484 gnome_vfs_close( handle
);
1485 return createTempStream( xEnv
);
1488 if (result
!= GNOME_VFS_OK
)
1489 cancelCommandExecution( result
, xEnv
);
1492 xIn
= new ::gvfs::Stream( handle
, &m_info
);
1498 Content::feedSink( uno::Reference
< uno::XInterface
> aSink
,
1499 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1504 uno::Reference
< io::XOutputStream
> xOut
1505 = uno::Reference
< io::XOutputStream
>(aSink
, uno::UNO_QUERY
);
1506 uno::Reference
< io::XActiveDataSink
> xDataSink
1507 = uno::Reference
< io::XActiveDataSink
>(aSink
, uno::UNO_QUERY
);
1509 if ( !xOut
.is() && !xDataSink
.is() )
1512 uno::Reference
< io::XInputStream
> xIn
= createInputStream( xEnv
);
1517 copyData( xIn
, xOut
);
1519 if ( xDataSink
.is() )
1520 xDataSink
->setInputStream( xIn
);
1527 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
1528 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)"
1532 vfs_authentication_callback (gconstpointer in_void
,
1536 gpointer callback_data
)
1538 task::XInteractionHandler
*xIH
;
1540 #if OSL_DEBUG_LEVEL > 1
1541 g_warning ("Full authentication callback (%p) ...", callback_data
);
1544 if( !( xIH
= (task::XInteractionHandler
*) callback_data
) )
1547 const GnomeVFSModuleCallbackFullAuthenticationIn
*in
=
1548 (const GnomeVFSModuleCallbackFullAuthenticationIn
*) in_void
;
1549 GnomeVFSModuleCallbackFullAuthenticationOut
*out
=
1550 (GnomeVFSModuleCallbackFullAuthenticationOut
*) out_void
;
1552 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1553 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn
) == in_size
&&
1554 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut
) == out_size
);
1556 #if OSL_DEBUG_LEVEL > 1
1557 # define NNIL(x) (x?x:"<Null>")
1558 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' "
1559 "port %d auth_t '%s' user '%s' domain '%s' "
1560 "def user '%s', def domain '%s'",
1561 (int) in
->flags
, NNIL(in
->uri
), NNIL(in
->protocol
),
1562 NNIL(in
->server
), NNIL(in
->object
),
1563 (int) in
->port
, NNIL(in
->authtype
), NNIL(in
->username
), NNIL(in
->domain
),
1564 NNIL(in
->default_user
), NNIL(in
->default_domain
));
1568 ucbhelper::SimpleAuthenticationRequest::EntityType
1569 eDomain
, eUserName
, ePassword
;
1570 OUString aHostName
, aDomain
, aUserName
, aPassword
;
1572 aHostName
= GnomeToOUString( in
->server
);
1574 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
)
1576 aDomain
= GnomeToOUString( in
->domain
);
1577 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
;
1578 if (aDomain
.isEmpty())
1579 aDomain
= GnomeToOUString( in
->default_domain
);
1581 else // no underlying capability to display realm otherwise
1582 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
;
1584 aUserName
= GnomeToOUString( in
->username
);
1585 if (aUserName
.isEmpty())
1586 aUserName
= GnomeToOUString( in
->default_user
);
1587 eUserName
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
) ?
1588 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1589 (!aUserName
.isEmpty() ?
1590 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
:
1591 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
);
1593 // No suggested password.
1594 ePassword
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
) ?
1595 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1596 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
;
1598 // Really, really bad things happen if we don't provide
1599 // the same user/password as was entered last time if
1600 // we failed to authenticate - infinite looping / flickering
1601 // madness etc. [ nice infrastructure ! ]
1602 static OUString aLastUserName
, aLastPassword
;
1603 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
)
1605 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1606 aUserName
= aLastUserName
;
1607 aPassword
= aLastPassword
;
1610 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
1611 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in
->uri
),
1612 aHostName
, eDomain
, aDomain
,
1613 eUserName
, aUserName
,
1614 ePassword
, aPassword
);
1616 xIH
->handle( xRequest
.get() );
1618 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
1619 = xRequest
->getSelection();
1621 if ( xSelection
.is() ) {
1622 // Handler handled the request.
1623 uno::Reference
< task::XInteractionAbort
> xAbort(xSelection
.get(), uno::UNO_QUERY
);
1624 if ( !xAbort
.is() ) {
1625 const rtl::Reference
<
1626 ucbhelper::InteractionSupplyAuthentication
> & xSupp
1627 = xRequest
->getAuthenticationSupplier();
1629 OUString aNewDomain
, aNewUserName
, aNewPassword
;
1631 aNewUserName
= xSupp
->getUserName();
1632 if ( !aNewUserName
.isEmpty() )
1633 aUserName
= aNewUserName
;
1634 aNewDomain
= xSupp
->getRealm();
1635 if ( !aNewDomain
.isEmpty() )
1636 aDomain
= aNewDomain
;
1637 aNewPassword
= xSupp
->getPassword();
1638 if ( !aNewPassword
.isEmpty() )
1639 aPassword
= aNewPassword
;
1642 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1643 aLastUserName
= aUserName
;
1644 aLastPassword
= aPassword
;
1647 out
->username
= OUStringToGnome( aUserName
);
1648 out
->domain
= OUStringToGnome( aDomain
);
1649 out
->password
= OUStringToGnome( aPassword
);
1650 out
->save_password
= xSupp
->getRememberPasswordMode();
1652 #if OSL_DEBUG_LEVEL > 1
1653 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password",
1654 out
->username
, out
->domain
, out
->password
,
1655 out
->save_password
? "save" : "don't save");
1659 out
->abort_auth
= TRUE
;
1662 out
->abort_auth
= TRUE
;
1666 vfs_authentication_old_callback (gconstpointer in_void
,
1670 gpointer callback_data
)
1673 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data
);
1675 const GnomeVFSModuleCallbackAuthenticationIn
*in
=
1676 (const GnomeVFSModuleCallbackAuthenticationIn
*) in_void
;
1677 GnomeVFSModuleCallbackAuthenticationOut
*out
=
1678 (GnomeVFSModuleCallbackAuthenticationOut
*) out_void
;
1680 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1681 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn
) == in_size
&&
1682 sizeof (GnomeVFSModuleCallbackAuthenticationOut
) == out_size
);
1684 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in
= {
1685 (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1686 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
|
1687 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
|
1688 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
),
1689 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1690 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out
= { 0, 0, 0, 0, 0, 0, 0, 0 };
1692 // Map the old style input auth. data to the new style structure.
1693 if (in
->previous_attempt_failed
)
1694 mapped_in
.flags
= (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1696 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
);
1698 GnomeVFSURI
*pURI
= NULL
;
1699 // Urk - parse all this from the URL ...
1700 mapped_in
.uri
= in
->uri
;
1703 pURI
= gnome_vfs_uri_new( in
->uri
);
1704 mapped_in
.protocol
= (char *) gnome_vfs_uri_get_scheme (pURI
);
1705 mapped_in
.server
= (char *) gnome_vfs_uri_get_host_name (pURI
);
1706 mapped_in
.port
= gnome_vfs_uri_get_host_port (pURI
);
1707 mapped_in
.username
= (char *) gnome_vfs_uri_get_user_name (pURI
);
1709 mapped_in
.domain
= in
->realm
;
1710 mapped_in
.default_user
= mapped_in
.username
;
1711 mapped_in
.default_domain
= mapped_in
.domain
;
1713 vfs_authentication_callback ((gconstpointer
) &mapped_in
,
1715 (gpointer
) &mapped_out
,
1716 sizeof (mapped_out
),
1720 gnome_vfs_uri_unref (pURI
);
1722 // Map the new style auth. out data to the old style out structure.
1723 out
->username
= mapped_out
.username
;
1724 out
->password
= mapped_out
.password
;
1725 g_free (mapped_out
.domain
);
1726 g_free (mapped_out
.keyring
);
1731 auth_destroy (gpointer data
)
1733 task::XInteractionHandler
*xIH
;
1734 if( ( xIH
= ( task::XInteractionHandler
* )data
) )
1738 // This sucks, but gnome-vfs doesn't much like
1739 // repeated set / unsets - so we have to compensate.
1740 GPrivate
*auth_queue
= NULL
;
1742 void auth_queue_destroy( gpointer data
)
1745 GQueue
*vq
= (GQueue
*) data
;
1747 for (l
= vq
->head
; l
; l
= l
->next
)
1748 auth_destroy (l
->data
);
1754 refresh_auth( GQueue
*vq
)
1758 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
);
1759 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
);
1761 for (l
= vq
->head
; l
; l
= l
->next
) {
1763 gnome_vfs_module_callback_push
1764 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
,
1765 vfs_authentication_old_callback
, l
->data
, NULL
);
1766 gnome_vfs_module_callback_push
1767 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
,
1768 vfs_authentication_callback
, l
->data
, NULL
);
1774 gvfs::Authentication::Authentication(
1775 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1778 uno::Reference
< task::XInteractionHandler
> xIH
;
1781 xIH
= xEnv
->getInteractionHandler();
1786 if( !(vq
= (GQueue
*)g_private_get( auth_queue
) ) ) {
1788 g_private_set( auth_queue
, vq
);
1791 g_queue_push_head( vq
, (gpointer
) xIH
.get() );
1795 gvfs::Authentication::~Authentication()
1800 vq
= (GQueue
*)g_private_get( auth_queue
);
1802 data
= g_queue_pop_head( vq
);
1803 auth_destroy (data
);
1808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */