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
, std::exception
)
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
, std::exception
)
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 ),
277 uno::Any SAL_CALL
Content::execute(
278 const ucb::Command
& aCommand
,
279 sal_Int32
/*CommandId*/,
280 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
281 throw( uno::Exception
,
282 ucb::CommandAbortedException
,
283 uno::RuntimeException
)
287 #if OSL_DEBUG_LEVEL > 1
289 uno::Reference
< task::XInteractionHandler
> xIH
;
292 xIH
= xEnv
->getInteractionHandler();
293 g_warning( "Execute command: '%s' with %s interaction env",
294 OUStringToGnome( aCommand
.Name
),
295 xIH
.is() ? "" : "NO" );
299 #define COMMAND_IS(cmd,name) ( (cmd).Name == name )
301 if ( COMMAND_IS( aCommand
, "getPropertyValues" ) ) {
302 uno::Sequence
< beans::Property
> Properties
;
304 if ( !( aCommand
.Argument
>>= Properties
) )
305 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
307 aRet
<<= getPropertyValues( Properties
, xEnv
);
309 } else if ( COMMAND_IS( aCommand
, "setPropertyValues" ) ) {
310 uno::Sequence
< beans::PropertyValue
> aProperties
;
312 if ( !( aCommand
.Argument
>>= aProperties
) ||
313 !aProperties
.getLength() )
314 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
316 aRet
<<= setPropertyValues( aProperties
, xEnv
);
318 } else if ( COMMAND_IS( aCommand
, "getPropertySetInfo" ) ) {
319 aRet
<<= getPropertySetInfo( xEnv
, false );
321 } else if ( COMMAND_IS( aCommand
, "getCommandInfo" ) ) {
322 aRet
<<= getCommandInfo( xEnv
, false );
324 } else if ( COMMAND_IS( aCommand
, "open" ) ) {
325 ucb::OpenCommandArgument2 aOpenCommand
;
326 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
327 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
329 sal_Bool bOpenFolder
=
330 ( ( aOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
331 ( aOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
332 ( aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
) );
334 if ( bOpenFolder
&& isFolder( xEnv
) ) {
335 uno::Reference
< ucb::XDynamicResultSet
> xSet
336 = new DynamicResultSet( m_xContext
, this, aOpenCommand
, xEnv
);
339 } else if ( aOpenCommand
.Sink
.is() ) {
341 if ( ( aOpenCommand
.Mode
342 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
344 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) ) {
345 ucbhelper::cancelCommandExecution
346 ( uno::makeAny ( ucb::UnsupportedOpenModeException
348 static_cast< cppu::OWeakObject
* >( this ),
349 sal_Int16( aOpenCommand
.Mode
) ) ),
352 if ( !feedSink( aOpenCommand
.Sink
, xEnv
) ) {
353 // Note: aOpenCommand.Sink may contain an XStream
354 // implementation. Support for this type of
355 // sink is optional...
357 g_warning ("Failed to load data from '%s'", getURI());
359 ucbhelper::cancelCommandExecution
360 ( uno::makeAny (ucb::UnsupportedDataSinkException
362 static_cast< cppu::OWeakObject
* >( this ),
363 aOpenCommand
.Sink
) ),
369 g_warning ("Open falling through ...");
372 } else if ( COMMAND_IS( aCommand
, "createNewContent" ) && isFolder( xEnv
) ) {
373 ucb::ContentInfo arg
;
374 if ( !( aCommand
.Argument
>>= arg
) )
375 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
377 aRet
<<= createNewContent( arg
);
379 } else if ( COMMAND_IS( aCommand
, "insert" ) ) {
380 ucb::InsertCommandArgument arg
;
381 if ( !( aCommand
.Argument
>>= arg
) )
382 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
384 insert( arg
.Data
, arg
.ReplaceExisting
, xEnv
);
386 } else if ( COMMAND_IS( aCommand
, "delete" ) ) {
388 sal_Bool bDeletePhysical
= sal_False
;
389 aCommand
.Argument
>>= bDeletePhysical
;
391 OString aURI
= getOURI();
392 GnomeVFSResult result
= gnome_vfs_unlink (aURI
.getStr());
394 if (result
!= GNOME_VFS_OK
)
395 cancelCommandExecution( result
, xEnv
, sal_True
);
397 destroy( bDeletePhysical
);
399 } else if ( COMMAND_IS( aCommand
, "transfer" ) && isFolder( xEnv
) ) {
400 ucb::TransferInfo transferArgs
;
402 if ( !( aCommand
.Argument
>>= transferArgs
) )
403 ucbhelper::cancelCommandExecution( getBadArgExcept(), xEnv
);
405 transfer( transferArgs
, xEnv
);
407 } else { // Unsupported
409 g_warning( "Unsupported command: '%s'",
410 OUStringToGnome( aCommand
.Name
) );
412 ucbhelper::cancelCommandExecution
413 ( uno::makeAny( ucb::UnsupportedCommandException
415 static_cast< cppu::OWeakObject
* >( this ) ) ),
423 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
424 throw( uno::RuntimeException
)
426 // FIXME: we should use the GnomeVFSCancellation APIs here ...
430 // XContentCreator methods.
433 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
434 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
435 throw( uno::RuntimeException
)
437 if ( isFolder( xEnv
) )
439 uno::Sequence
< ucb::ContentInfo
> seq(2);
441 // Minimum set of props we really need
442 uno::Sequence
< beans::Property
> props( 1 );
443 props
[0] = beans::Property(
446 cppu::UnoType
<OUString
>::get(),
447 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
);
450 seq
[0].Type
= OUString( GVFS_FILE_TYPE
);
451 seq
[0].Attributes
= ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
452 ucb::ContentInfoAttribute::KIND_DOCUMENT
);
453 seq
[0].Properties
= props
;
456 seq
[1].Type
= OUString( GVFS_FOLDER_TYPE
);
457 seq
[1].Attributes
= ucb::ContentInfoAttribute::KIND_FOLDER
;
458 seq
[1].Properties
= props
;
464 return uno::Sequence
< ucb::ContentInfo
>();
468 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
469 throw( uno::RuntimeException
)
471 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
474 uno::Reference
< ucb::XContent
> SAL_CALL
475 Content::createNewContent( const ucb::ContentInfo
& Info
)
476 throw( uno::RuntimeException
)
478 bool create_document
;
481 if ( Info
.Type
== GVFS_FILE_TYPE
)
482 create_document
= true;
483 else if ( Info
.Type
== GVFS_FOLDER_TYPE
)
484 create_document
= false;
487 g_warning( "Failed to create new content '%s'",
488 OUStringToGnome( Info
.Type
) );
490 return uno::Reference
< ucb::XContent
>();
493 #if OSL_DEBUG_LEVEL > 1
494 g_warning( "createNewContent (%d)", (int) create_document
);
497 OUString aURL
= getOUURI();
499 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
502 name
= create_document
? "[New_Content]" : "[New_Collection]";
503 // This looks problematic to me cf. webdav
504 aURL
+= OUString::createFromAscii( name
);
506 uno::Reference
< ucb::XContentIdentifier
> xId
507 ( new ::ucbhelper::ContentIdentifier( aURL
) );
510 return new ::gvfs::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
511 } catch ( ucb::ContentCreationException
& ) {
512 return uno::Reference
< ucb::XContent
>();
516 OUString
Content::getParentURL()
520 // <scheme>://foo -> ""
521 // <scheme>://foo/ -> ""
522 // <scheme>://foo/bar -> <scheme>://foo/
523 // <scheme>://foo/bar/ -> <scheme>://foo/
524 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
526 OUString aURL
= getOUURI();
528 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
529 if ( nPos
== ( aURL
.getLength() - 1 ) ) {
530 // Trailing slash found. Skip.
531 nPos
= aURL
.lastIndexOf( '/', nPos
);
534 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
536 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
539 aParentURL
= aURL
.copy( 0, nPos
+ 1 );
541 #if OSL_DEBUG_LEVEL > 1
542 g_warning ("getParentURL '%s' -> '%s'",
543 getURI(), OUStringToOString
544 ( aParentURL
, RTL_TEXTENCODING_UTF8
).getStr() );
550 static util::DateTime
551 getDateFromUnix (time_t t
)
558 if ( osl_getDateTimeFromTimeValue( &tv
, &dt
) )
559 return util::DateTime( 0, dt
.Seconds
, dt
.Minutes
, dt
.Hours
,
560 dt
.Day
, dt
.Month
, dt
.Year
, false);
562 return util::DateTime();
565 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
566 const uno::Sequence
< beans::Property
>& rProperties
,
567 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
570 uno::Sequence
< beans::Property
> allProperties
;
574 const beans::Property
* pProps
;
576 if( rProperties
.getLength() ) {
577 nProps
= rProperties
.getLength();
578 pProps
= rProperties
.getConstArray();
580 allProperties
= getPropertySetInfo( xEnv
)->getProperties();
581 nProps
= allProperties
.getLength();
582 pProps
= allProperties
.getConstArray();
585 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
586 = new ::ucbhelper::PropertyValueSet( m_xContext
);
588 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
589 for( sal_Int32 n
= 0; n
< nProps
; ++n
) {
590 const beans::Property
& rProp
= pProps
[ n
];
592 if ( rProp
.Name
== "Title" ) {
594 if (m_info
.name
[0] == '/')
595 g_warning ("Odd NFS title on item '%s' == '%s'",
596 getURI(), m_info
.name
);
597 xRow
->appendString( rProp
, GnomeToOUString( m_info
.name
) );
599 xRow
->appendVoid( rProp
);
602 else if ( rProp
.Name
== "ContentType" )
603 xRow
->appendString( rProp
, getContentType () );
605 else if ( rProp
.Name
== "IsDocument" ) {
606 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
607 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_REGULAR
||
608 m_info
.type
== GNOME_VFS_FILE_TYPE_UNKNOWN
) );
610 xRow
->appendVoid( rProp
);
612 else if ( rProp
.Name
== "IsFolder" ) {
613 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
)
614 xRow
->appendBoolean( rProp
, ( m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) );
616 xRow
->appendVoid( rProp
);
618 else if ( rProp
.Name
== "IsReadOnly" ) {
620 GnomeVFSFileInfo
* fileInfo
= gnome_vfs_file_info_new ();
622 OString aURI
= getOURI();
623 gnome_vfs_get_file_info
624 ( aURI
.getStr(), fileInfo
,
625 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
);
627 if (fileInfo
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_ACCESS
) {
628 bool read_only
= true;
630 if (fileInfo
->permissions
& GNOME_VFS_PERM_ACCESS_WRITABLE
)
633 xRow
->appendBoolean( rProp
, read_only
);
635 xRow
->appendVoid( rProp
);
636 gnome_vfs_file_info_unref (fileInfo
);
638 else if ( rProp
.Name
== "Size" ) {
639 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
)
640 xRow
->appendLong( rProp
, m_info
.size
);
642 xRow
->appendVoid( rProp
);
644 else if ( rProp
.Name
== "IsHidden" )
646 xRow
->appendBoolean( rProp
, m_info
.name
[0] == '.' );
648 xRow
->appendVoid( rProp
);
650 else if ( rProp
.Name
== "IsVolume" || rProp
.Name
== "IsCompactDisk" )
651 xRow
->appendBoolean( rProp
, false );
653 else if ( rProp
.Name
== "DateCreated" ) {
654 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_CTIME
)
655 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.ctime
) );
657 xRow
->appendVoid( rProp
);
660 else if ( rProp
.Name
== "DateModified" ) {
661 if (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
662 xRow
->appendTimestamp( rProp
, getDateFromUnix( m_info
.mtime
) );
664 xRow
->appendVoid( rProp
);
667 else if ( rProp
.Name
== "MediaType" ) {
668 // We do this by sniffing in gnome-vfs; rather expensively.
670 g_warning ("FIXME: Requested mime-type - an expensive op. indeed!");
672 xRow
->appendVoid( rProp
);
673 } else if ( rProp
.Name
== "CreatableContentsInfo" )
674 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
677 xRow
->appendVoid( rProp
);
680 #if OSL_DEBUG_LEVEL > 1
681 g_warning ("getPropertyValues on '%s' %d properties returned (of %d)",
682 getURI(), 0, (int)nProps
);
685 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
688 static lang::IllegalAccessException
689 getReadOnlyException( Content
*ctnt
)
691 return lang::IllegalAccessException
692 ( OUString("Property is read-only!"),
693 static_cast< cppu::OWeakObject
* >( ctnt
) );
697 Content::makeNewURL( const char */
*newName*/
)
699 OUString aNewURL
= getParentURL();
700 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
703 char *name
= gnome_vfs_escape_string( m_info
.name
);
704 aNewURL
+= GnomeToOUString( name
);
710 // This is slightly complicated by needing to support either 'move' or 'setname'
712 Content::doSetFileInfo( const GnomeVFSFileInfo
*newInfo
,
713 GnomeVFSSetFileInfoMask setMask
,
714 const uno::Reference
< ucb::XCommandEnvironment
>& /*xEnv*/ )
716 GnomeVFSResult result
= GNOME_VFS_OK
;
718 g_assert (!m_bTransient
);
720 OString aURI
= getOURI();
722 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
724 // The simple approach:
725 if( setMask
!= GNOME_VFS_SET_FILE_INFO_NONE
)
726 result
= gnome_vfs_set_file_info
// missed a const in the API there
727 ( aURI
.getStr(), (GnomeVFSFileInfo
*)newInfo
, setMask
);
729 if ( result
== GNOME_VFS_ERROR_NOT_SUPPORTED
&&
730 ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) ) {
731 // Try a move instead
733 g_warning( "SetFileInfo not supported on '%s'", getURI() );
736 char *newURI
= OUStringToGnome( makeNewURL( newInfo
->name
) );
738 result
= gnome_vfs_move (aURI
.getStr(), newURI
, FALSE
);
747 uno::Sequence
< uno::Any
> Content::setPropertyValues(
748 const uno::Sequence
< beans::PropertyValue
>& rValues
,
749 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
752 GnomeVFSFileInfo newInfo
;
753 int setMask
= GNOME_VFS_SET_FILE_INFO_NONE
;
757 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
759 gnome_vfs_file_info_copy( &newInfo
, &m_info
);
761 Authentication
aAuth( xEnv
);
763 int nChanged
= 0, nTitlePos
= 0;
764 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
765 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
767 beans::PropertyChangeEvent aEvent
;
768 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
769 aEvent
.Further
= sal_False
;
770 aEvent
.PropertyHandle
= -1;
771 // aEvent.PropertyName = fill in later ...
775 int nCount
= rValues
.getLength();
776 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
778 for ( sal_Int32 n
= 0; n
< nCount
; ++n
) {
779 const beans::PropertyValue
& rValue
= pValues
[ n
];
781 #if OSL_DEBUG_LEVEL > 1
782 g_warning( "Set prop '%s'", OUStringToGnome( rValue
.Name
) );
784 if ( rValue
.Name
== "ContentType" ||
785 rValue
.Name
== "MediaType" ||
786 rValue
.Name
== "IsDocument" ||
787 rValue
.Name
== "IsFolder" ||
788 rValue
.Name
== "Size" ||
789 rValue
.Name
== "CreatableContentsInfo" )
790 aRet
[ n
] <<= getReadOnlyException( this );
792 else if ( rValue
.Name
== "Title" ) {
793 if ( rValue
.Value
>>= aNewTitle
) {
794 if ( aNewTitle
.isEmpty() )
795 aRet
[ n
] <<= lang::IllegalArgumentException
796 ( OUString("Empty title not allowed!"),
797 static_cast< cppu::OWeakObject
* >( this ), -1 );
799 char *newName
= OUStringToGnome( aNewTitle
);
801 if( !newName
|| !m_info
.name
|| strcmp( newName
, m_info
.name
) ) {
802 #if OSL_DEBUG_LEVEL > 1
803 g_warning ("Set new name to '%s'", newName
);
806 aEvent
.PropertyName
= "Title";
807 aEvent
.OldValue
= uno::makeAny( GnomeToOUString( newInfo
.name
) );
808 aEvent
.NewValue
= uno::makeAny( aNewTitle
);
809 aChanges
.getArray()[ nChanged
] = aEvent
;
810 nTitlePos
= nChanged
++;
812 newInfo
.name
= newName
;
813 setMask
|= GNOME_VFS_SET_FILE_INFO_NAME
;
818 aRet
[ n
] <<= beans::IllegalTypeException
819 ( OUString("Property value has wrong type!"),
820 static_cast< cppu::OWeakObject
* >( this ) );
822 } else if ( rValue
.Name
== "DateCreated" || rValue
.Name
== "DateModified" ) {
823 // FIXME: should be able to set the timestamps
824 aRet
[ n
] <<= getReadOnlyException( this );
827 g_warning( "Unhandled property '%s'", OUStringToGnome( rValue
.Name
) );
829 aRet
[ n
] <<= getReadOnlyException( this );
833 GnomeVFSResult result
= GNOME_VFS_OK
;
835 if ( !m_bTransient
&&
836 ( result
= doSetFileInfo( &newInfo
,
837 (GnomeVFSSetFileInfoMask
) setMask
,
838 xEnv
) ) != GNOME_VFS_OK
) {
839 for (int i
= 0; i
< nChanged
; i
++)
840 aRet
[ i
] <<= mapVFSException( result
, sal_True
);
844 if ( result
== GNOME_VFS_OK
) {
845 gnome_vfs_file_info_copy( &m_info
, &newInfo
);
847 if ( setMask
& GNOME_VFS_SET_FILE_INFO_NAME
) {
848 uno::Reference
< ucb::XContentIdentifier
> xNewId
849 = new ::ucbhelper::ContentIdentifier( makeNewURL( newInfo
.name
) );
852 if (!exchangeIdentity( xNewId
) )
853 aRet
[ nTitlePos
] <<= uno::Exception
854 ( OUString("Exchange failed!"),
855 static_cast< cppu::OWeakObject
* >( this ) );
859 gnome_vfs_file_info_clear( &newInfo
);
861 if ( nChanged
> 0 ) {
863 aChanges
.realloc( nChanged
);
864 notifyPropertiesChange( aChanges
);
870 void Content::queryChildren( ContentRefList
& rChildren
)
872 // Obtain a list with a snapshot of all currently instantiated contents
873 // from provider and extract the contents which are direct children
876 ::ucbhelper::ContentRefList aAllContents
;
877 m_xProvider
->queryExistingContents( aAllContents
);
879 OUString aURL
= getOUURI();
880 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
882 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
885 sal_Int32 nLen
= aURL
.getLength();
887 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
888 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
890 while ( it
!= end
) {
891 ::ucbhelper::ContentImplHelperRef xChild
= (*it
);
893 = xChild
->getIdentifier()->getContentIdentifier();
895 // Is aURL a prefix of aChildURL?
896 if ( ( aChildURL
.getLength() > nLen
) &&
897 ( aChildURL
.startsWith( aURL
) ) ) {
898 sal_Int32 nPos
= nLen
;
899 nPos
= aChildURL
.indexOf( '/', nPos
);
901 if ( ( nPos
== -1 ) ||
902 ( nPos
== ( aChildURL
.getLength() - 1 ) ) ) {
903 // No further slashes / only a final slash. It's a child!
904 rChildren
.push_back( ::gvfs::Content::ContentRef
905 (static_cast< ::gvfs::Content
* >(xChild
.get() ) ) );
912 void Content::insert(
913 const uno::Reference
< io::XInputStream
> &xInputStream
,
914 sal_Bool bReplaceExisting
,
915 const uno::Reference
< ucb::XCommandEnvironment
> &xEnv
)
916 throw( uno::Exception
)
918 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
920 #if OSL_DEBUG_LEVEL > 1
921 g_warning( "Insert '%s' (%d) (0x%x:%d)", getURI(), bReplaceExisting
,
922 m_info
.valid_fields
, m_info
.type
);
925 GnomeVFSResult result
= getInfo( xEnv
);
926 // a racy design indeed.
927 if( !bReplaceExisting
&& !m_bTransient
&&
928 result
!= GNOME_VFS_ERROR_NOT_FOUND
) {
930 g_warning ("Nasty error inserting to '%s' ('%s')",
931 getURI(), gnome_vfs_result_to_string( result
));
933 cancelCommandExecution( GNOME_VFS_ERROR_FILE_EXISTS
, xEnv
, sal_True
);
936 if ( m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
937 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
) {
938 OString aURI
= getOURI();
941 perm
= ( GNOME_VFS_PERM_USER_ALL
|
942 GNOME_VFS_PERM_GROUP_READ
|
943 GNOME_VFS_PERM_OTHER_READ
);
945 #if OSL_DEBUG_LEVEL > 1
946 g_warning ("Make directory");
948 result
= gnome_vfs_make_directory( aURI
.getStr(), perm
);
950 if( result
!= GNOME_VFS_OK
)
951 cancelCommandExecution( result
, xEnv
, sal_True
);
956 if ( !xInputStream
.is() ) {
957 // FIXME: slightly unclear whether to accept this and create an empty file
958 ucbhelper::cancelCommandExecution
960 ( ucb::MissingInputStreamException
962 static_cast< cppu::OWeakObject
* >( this ) ) ),
966 GnomeVFSHandle
*handle
= NULL
;
967 OString aURI
= getOURI();
969 result
= GNOME_VFS_ERROR_GENERIC
;
970 if ( bReplaceExisting
) {
971 Authentication
aAuth( xEnv
);
972 result
= gnome_vfs_open( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
);
975 if ( result
!= GNOME_VFS_OK
) {
977 Authentication
aAuth( xEnv
);
979 perm
= ( ( GNOME_VFS_PERM_USER_WRITE
| GNOME_VFS_PERM_USER_READ
) |
980 ( GNOME_VFS_PERM_GROUP_WRITE
| GNOME_VFS_PERM_GROUP_READ
) );
982 result
= gnome_vfs_create
983 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_WRITE
, TRUE
, perm
);
986 if( result
!= GNOME_VFS_OK
)
987 cancelCommandExecution( result
, xEnv
, sal_True
);
989 if ( !xInputStream
.is() ) {
990 result
= gnome_vfs_close( handle
);
991 if (result
!= GNOME_VFS_OK
)
992 cancelCommandExecution( result
, xEnv
, sal_True
);
994 } else { // copy it over
995 uno::Reference
< io::XOutputStream
> xOutput
=
996 new gvfs::Stream( handle
, &m_info
);
998 copyData( xInputStream
, xOutput
);
1002 m_bTransient
= sal_False
;
1008 void Content::transfer(const ucb::TransferInfo
& /*rArgs*/,
1009 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1010 throw( uno::Exception
)
1012 // FIXME: see gnome-vfs-xfer.h - but we need to be able to easily
1013 // detect which are gnome-vfs owned URI types ...
1014 ucbhelper::cancelCommandExecution
1016 ( ucb::InteractiveBadTransferURLException
1017 ( OUString("Unsupported URL scheme!"),
1018 static_cast< cppu::OWeakObject
* >( this ) ) ),
1022 void Content::destroy( sal_Bool bDeletePhysical
)
1023 throw( uno::Exception
)
1025 // @@@ take care about bDeletePhysical -> trashcan support
1026 uno::Reference
< ucb::XContent
> xThis
= this;
1030 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1032 // Process instantiated children...
1033 ::gvfs::Content::ContentRefList aChildren
;
1034 queryChildren( aChildren
);
1036 ContentRefList::const_iterator it
= aChildren
.begin();
1037 ContentRefList::const_iterator end
= aChildren
.end();
1039 while ( it
!= end
) {
1040 (*it
)->destroy( bDeletePhysical
);
1045 // Used by the 'setPropertyValues' method for
1046 // propagating the renaming of a Content.
1047 sal_Bool
Content::exchangeIdentity(
1048 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1053 uno::Reference
< ucb::XContent
> xThis
= this;
1055 #if OSL_DEBUG_LEVEL > 1
1056 g_warning( "exchangeIdentity from '%s' to '%s'",
1057 getURI(), OUStringToGnome( xNewId
->getContentIdentifier() ) );
1060 if ( m_bTransient
) {
1061 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1062 /* FIXME: can we not screw up an identically named
1063 * Content pointing to ourself here ? */
1064 m_xIdentifier
= xNewId
;
1068 OUString aOldURL
= getOUURI();
1070 // Exchange own identitity.
1071 if ( exchange( xNewId
) ) {
1073 // Process instantiated children...
1074 ContentRefList aChildren
;
1075 queryChildren( aChildren
);
1077 ContentRefList::const_iterator it
= aChildren
.begin();
1078 ContentRefList::const_iterator end
= aChildren
.end();
1080 while ( it
!= end
) {
1081 ContentRef xChild
= (*it
);
1083 // Create new content identifier for the child...
1084 uno::Reference
< ucb::XContentIdentifier
>
1085 xOldChildId
= xChild
->getIdentifier();
1086 OUString aOldChildURL
1087 = xOldChildId
->getContentIdentifier();
1088 OUString aNewChildURL
1089 = aOldChildURL
.replaceAt(
1091 aOldURL
.getLength(),
1092 xNewId
->getContentIdentifier() );
1093 uno::Reference
< ucb::XContentIdentifier
>
1095 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1097 if ( !xChild
->exchangeIdentity( xNewChildId
) )
1109 Content::getInfo( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1111 GnomeVFSResult result
;
1112 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1115 result
= GNOME_VFS_OK
;
1117 else if ( !m_info
.valid_fields
) {
1118 OString aURI
= getOURI();
1119 Authentication
aAuth( xEnv
);
1120 result
= gnome_vfs_get_file_info
1121 ( aURI
.getStr(), &m_info
, GNOME_VFS_FILE_INFO_DEFAULT
);
1122 if (result
!= GNOME_VFS_OK
)
1126 "gnome_vfs_get_file_info for <" << aURI
<< "> failed with \""
1127 << gnome_vfs_result_to_string(result
) << "\" (" << +result
1129 gnome_vfs_file_info_clear( &m_info
);
1132 result
= GNOME_VFS_OK
;
1133 #if OSL_DEBUG_LEVEL > 1
1134 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)",
1135 getURI(), gnome_vfs_result_to_string( result
),
1136 result
, m_info
.valid_fields
);
1142 Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1144 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1146 return (m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_TYPE
&&
1147 m_info
.type
== GNOME_VFS_FILE_TYPE_DIRECTORY
);
1150 uno::Any
Content::mapVFSException( const GnomeVFSResult result
, sal_Bool bWrite
)
1152 uno::Any aException
;
1153 const char *gvfs_message
;
1155 uno::Sequence
< uno::Any
> aArgs( 1 );
1157 #if OSL_DEBUG_LEVEL > 1
1158 g_warning ("Map VFS exception '%s' (%d)",
1159 gnome_vfs_result_to_string( result
), result
);
1162 if ((gvfs_message
= gnome_vfs_result_to_string (result
)))
1163 message
= GnomeToOUString( gvfs_message
);
1167 g_warning("VFS_OK mapped to exception.");
1169 case GNOME_VFS_ERROR_EOF
:
1170 g_warning ("VFS_EOF not handled somewhere.");
1172 case GNOME_VFS_ERROR_NOT_FOUND
:
1173 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
1175 ucb::InteractiveAugmentedIOException
1176 ( OUString("Not found!"),
1177 static_cast< cppu::OWeakObject
* >( this ),
1178 task::InteractionClassification_ERROR
,
1179 ucb::IOErrorCode_NOT_EXISTING
,
1182 case GNOME_VFS_ERROR_BAD_PARAMETERS
:
1184 lang::IllegalArgumentException
1186 static_cast< cppu::OWeakObject
* >( this ),
1189 case GNOME_VFS_ERROR_GENERIC
:
1190 case GNOME_VFS_ERROR_INTERNAL
:
1191 case GNOME_VFS_ERROR_NOT_SUPPORTED
:
1193 g_warning ("Internal - un-mapped error");
1195 aException
<<= io::IOException();
1197 case GNOME_VFS_ERROR_IO
:
1200 ucb::InteractiveNetworkWriteException
1202 static_cast< cppu::OWeakObject
* >( this ),
1203 task::InteractionClassification_ERROR
,
1207 ucb::InteractiveNetworkReadException
1209 static_cast< cppu::OWeakObject
* >( this ),
1210 task::InteractionClassification_ERROR
,
1213 case GNOME_VFS_ERROR_HOST_NOT_FOUND
:
1214 case GNOME_VFS_ERROR_INVALID_HOST_NAME
:
1216 ucb::InteractiveNetworkResolveNameException
1218 static_cast< cppu::OWeakObject
* >( this ),
1219 task::InteractionClassification_ERROR
,
1222 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE
:
1223 case GNOME_VFS_ERROR_SERVICE_OBSOLETE
:
1224 case GNOME_VFS_ERROR_PROTOCOL_ERROR
:
1225 case GNOME_VFS_ERROR_NO_MASTER_BROWSER
:
1227 ucb::InteractiveNetworkConnectException
1229 static_cast< cppu::OWeakObject
* >( this ),
1230 task::InteractionClassification_ERROR
,
1234 case GNOME_VFS_ERROR_FILE_EXISTS
:
1235 aException
<<= ucb::NameClashException
1237 static_cast< cppu::OWeakObject
* >( this ),
1238 task::InteractionClassification_ERROR
,
1242 case GNOME_VFS_ERROR_INVALID_OPEN_MODE
:
1243 aException
<<= ucb::UnsupportedOpenModeException();
1246 case GNOME_VFS_ERROR_CORRUPTED_DATA
:
1247 case GNOME_VFS_ERROR_WRONG_FORMAT
:
1248 case GNOME_VFS_ERROR_BAD_FILE
:
1249 case GNOME_VFS_ERROR_TOO_BIG
:
1250 case GNOME_VFS_ERROR_NO_SPACE
:
1251 case GNOME_VFS_ERROR_READ_ONLY
:
1252 case GNOME_VFS_ERROR_INVALID_URI
:
1253 case GNOME_VFS_ERROR_NOT_OPEN
:
1254 case GNOME_VFS_ERROR_ACCESS_DENIED
:
1255 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES
:
1256 case GNOME_VFS_ERROR_NOT_A_DIRECTORY
:
1257 case GNOME_VFS_ERROR_IN_PROGRESS
:
1258 case GNOME_VFS_ERROR_INTERRUPTED
:
1259 case GNOME_VFS_ERROR_LOOP
:
1260 case GNOME_VFS_ERROR_NOT_PERMITTED
:
1261 case GNOME_VFS_ERROR_IS_DIRECTORY
:
1262 case GNOME_VFS_ERROR_NO_MEMORY
:
1263 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS
:
1264 case GNOME_VFS_ERROR_LOGIN_FAILED
:
1265 case GNOME_VFS_ERROR_CANCELLED
:
1266 case GNOME_VFS_ERROR_DIRECTORY_BUSY
:
1267 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY
:
1268 case GNOME_VFS_ERROR_TOO_MANY_LINKS
:
1269 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM
:
1270 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM
:
1271 case GNOME_VFS_ERROR_NAME_TOO_LONG
:
1273 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)",
1274 gnome_vfs_result_to_string( result
), result
);
1277 aException
<<= ucb::InteractiveNetworkGeneralException
1279 static_cast< cppu::OWeakObject
* >( this ),
1280 task::InteractionClassification_ERROR
);
1287 void Content::cancelCommandExecution(
1288 GnomeVFSResult result
,
1289 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
1290 sal_Bool bWrite
/* = sal_False */ )
1291 throw ( uno::Exception
)
1293 ucbhelper::cancelCommandExecution( mapVFSException( result
, bWrite
), xEnv
);
1297 uno::Sequence
< beans::Property
> Content::getProperties(
1298 const uno::Reference
< ucb::XCommandEnvironment
> & /*xEnv*/ )
1300 static const beans::Property aGenericProperties
[] = {
1301 beans::Property( OUString( "ContentType" ),
1302 -1, cppu::UnoType
<OUString
>::get(),
1303 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1304 beans::Property( OUString( "IsDocument" ),
1305 -1, cppu::UnoType
<bool>::get(),
1306 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1307 beans::Property( OUString( "IsFolder" ),
1308 -1, cppu::UnoType
<bool>::get(),
1309 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1310 beans::Property( OUString( "Title" ),
1311 -1, cppu::UnoType
<OUString
>::get(),
1312 beans::PropertyAttribute::BOUND
),
1314 beans::Property( OUString( "DateCreated" ),
1315 -1, cppu::UnoType
<util::DateTime
>::get(),
1316 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1317 beans::Property( OUString( "DateModified" ),
1318 -1, cppu::UnoType
<util::DateTime
>::get(),
1319 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1320 // FIXME: Too expensive for now (?)
1321 // beans::Property( OUString( "MediaType" ),
1322 // -1, cppu::UnoType<OUString>::get(),
1323 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1324 beans::Property( OUString( "Size" ),
1325 -1, cppu::UnoType
<sal_Int64
>::get(),
1326 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1327 beans::Property( OUString( "IsReadOnly" ),
1328 -1, cppu::UnoType
<bool>::get(),
1329 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1330 beans::Property( OUString( "IsVolume" ),
1331 -1, cppu::UnoType
<bool>::get(),
1332 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1333 beans::Property( OUString( "IsCompactDisk" ),
1334 -1, cppu::UnoType
<bool>::get(),
1335 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1336 beans::Property( OUString( "IsHidden" ),
1337 -1, cppu::UnoType
<bool>::get(),
1338 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1339 beans::Property( OUString( "CreatableContentsInfo" ),
1340 -1, cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
1341 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
)
1344 const int nProps
= sizeof (aGenericProperties
) / sizeof (aGenericProperties
[0]);
1346 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1350 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1351 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1353 static const ucb::CommandInfo aCommandInfoTable
[] = {
1354 // Required commands
1356 ( OUString( "getCommandInfo" ),
1357 -1, cppu::UnoType
<void>::get() ),
1359 ( OUString( "getPropertySetInfo" ),
1360 -1, cppu::UnoType
<void>::get() ),
1362 ( OUString( "getPropertyValues" ),
1363 -1, cppu::UnoType
<uno::Sequence
< beans::Property
>>::get() ),
1365 ( OUString( "setPropertyValues" ),
1366 -1, cppu::UnoType
<uno::Sequence
< beans::PropertyValue
>>::get() ),
1368 // Optional standard commands
1370 ( OUString( "delete" ),
1371 -1, cppu::UnoType
<bool>::get() ),
1373 ( OUString( "insert" ),
1374 -1, cppu::UnoType
<ucb::InsertCommandArgument
>::get() ),
1376 ( OUString( "open" ),
1377 -1, cppu::UnoType
<ucb::OpenCommandArgument2
>::get() ),
1379 // Folder Only, omitted if not a folder
1381 ( OUString( "transfer" ),
1382 -1, cppu::UnoType
<ucb::TransferInfo
>::get() ),
1384 ( OUString( "createNewContent" ),
1385 -1, cppu::UnoType
<ucb::ContentInfo
>::get() )
1389 = sizeof( aCommandInfoTable
) / sizeof( aCommandInfoTable
[ 0 ] );
1390 return uno::Sequence
< ucb::CommandInfo
>(
1391 aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2 );
1395 Content::getOUURI ()
1397 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1398 return m_xIdentifier
->getContentIdentifier();
1404 return OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8
);
1410 return OUStringToGnome( getOUURI() );
1414 Content::copyData( uno::Reference
< io::XInputStream
> xIn
,
1415 uno::Reference
< io::XOutputStream
> xOut
)
1417 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1419 g_return_if_fail( xIn
.is() && xOut
.is() );
1421 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1422 xOut
->writeBytes( theData
);
1424 xOut
->closeOutput();
1427 // Inherits an authentication context
1428 uno::Reference
< io::XInputStream
>
1429 Content::createTempStream(
1430 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1431 throw( uno::Exception
)
1433 GnomeVFSResult result
;
1434 GnomeVFSHandle
*handle
= NULL
;
1435 OString aURI
= getOURI();
1437 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1438 // Something badly wrong happened - can't seek => stream to a temporary file
1439 uno::Reference
< io::XOutputStream
> xTempOut
=
1440 uno::Reference
< io::XOutputStream
>
1441 ( io::TempFile::create( m_xContext
), uno::UNO_QUERY
);
1443 if ( !xTempOut
.is() )
1444 cancelCommandExecution( GNOME_VFS_ERROR_IO
, xEnv
);
1446 result
= gnome_vfs_open
1447 ( &handle
, aURI
.getStr(), GNOME_VFS_OPEN_READ
);
1448 if (result
!= GNOME_VFS_OK
)
1449 cancelCommandExecution( result
, xEnv
);
1451 uno::Reference
< io::XInputStream
> pStream
= new ::gvfs::Stream( handle
, &m_info
);
1452 copyData( pStream
, xTempOut
);
1454 return uno::Reference
< io::XInputStream
> ( xTempOut
, uno::UNO_QUERY
);
1457 uno::Reference
< io::XInputStream
>
1458 Content::createInputStream(
1459 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1460 throw( uno::Exception
)
1462 GnomeVFSHandle
*handle
= NULL
;
1463 GnomeVFSResult result
;
1464 uno::Reference
<io::XInputStream
> xIn
;
1466 Authentication
aAuth( xEnv
);
1467 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1470 OString aURI
= getOURI();
1472 if ( !(m_info
.valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_SIZE
) )
1473 return createTempStream( xEnv
);
1475 result
= gnome_vfs_open
1476 ( &handle
, aURI
.getStr(),
1477 (GnomeVFSOpenMode
) (GNOME_VFS_OPEN_READ
| GNOME_VFS_OPEN_RANDOM
) );
1479 if (result
== GNOME_VFS_ERROR_INVALID_OPEN_MODE
||
1480 result
== GNOME_VFS_ERROR_NOT_SUPPORTED
)
1481 return createTempStream( xEnv
);
1483 if (result
!= GNOME_VFS_OK
)
1484 cancelCommandExecution( result
, xEnv
);
1486 // Try a seek just to make sure it's Random access: some lie.
1487 result
= gnome_vfs_seek( handle
, GNOME_VFS_SEEK_START
, 0);
1488 if (result
== GNOME_VFS_ERROR_NOT_SUPPORTED
) {
1489 gnome_vfs_close( handle
);
1490 return createTempStream( xEnv
);
1493 if (result
!= GNOME_VFS_OK
)
1494 cancelCommandExecution( result
, xEnv
);
1497 xIn
= new ::gvfs::Stream( handle
, &m_info
);
1503 Content::feedSink( uno::Reference
< uno::XInterface
> aSink
,
1504 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1509 uno::Reference
< io::XOutputStream
> xOut
1510 = uno::Reference
< io::XOutputStream
>(aSink
, uno::UNO_QUERY
);
1511 uno::Reference
< io::XActiveDataSink
> xDataSink
1512 = uno::Reference
< io::XActiveDataSink
>(aSink
, uno::UNO_QUERY
);
1514 if ( !xOut
.is() && !xDataSink
.is() )
1517 uno::Reference
< io::XInputStream
> xIn
= createInputStream( xEnv
);
1522 copyData( xIn
, xOut
);
1524 if ( xDataSink
.is() )
1525 xDataSink
->setInputStream( xIn
);
1532 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
1533 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)"
1537 vfs_authentication_callback (gconstpointer in_void
,
1541 gpointer callback_data
)
1543 task::XInteractionHandler
*xIH
;
1545 #if OSL_DEBUG_LEVEL > 1
1546 g_warning ("Full authentication callback (%p) ...", callback_data
);
1549 if( !( xIH
= (task::XInteractionHandler
*) callback_data
) )
1552 const GnomeVFSModuleCallbackFullAuthenticationIn
*in
=
1553 (const GnomeVFSModuleCallbackFullAuthenticationIn
*) in_void
;
1554 GnomeVFSModuleCallbackFullAuthenticationOut
*out
=
1555 (GnomeVFSModuleCallbackFullAuthenticationOut
*) out_void
;
1557 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1558 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn
) == in_size
&&
1559 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut
) == out_size
);
1561 #if OSL_DEBUG_LEVEL > 1
1562 # define NNIL(x) (x?x:"<Null>")
1563 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' "
1564 "port %d auth_t '%s' user '%s' domain '%s' "
1565 "def user '%s', def domain '%s'",
1566 (int) in
->flags
, NNIL(in
->uri
), NNIL(in
->protocol
),
1567 NNIL(in
->server
), NNIL(in
->object
),
1568 (int) in
->port
, NNIL(in
->authtype
), NNIL(in
->username
), NNIL(in
->domain
),
1569 NNIL(in
->default_user
), NNIL(in
->default_domain
));
1573 ucbhelper::SimpleAuthenticationRequest::EntityType
1574 eDomain
, eUserName
, ePassword
;
1575 OUString aHostName
, aDomain
, aUserName
, aPassword
;
1577 aHostName
= GnomeToOUString( in
->server
);
1579 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
)
1581 aDomain
= GnomeToOUString( in
->domain
);
1582 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
;
1583 if (aDomain
.isEmpty())
1584 aDomain
= GnomeToOUString( in
->default_domain
);
1586 else // no underlying capability to display realm otherwise
1587 eDomain
= ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
;
1589 aUserName
= GnomeToOUString( in
->username
);
1590 if (aUserName
.isEmpty())
1591 aUserName
= GnomeToOUString( in
->default_user
);
1592 eUserName
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
) ?
1593 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1594 (!aUserName
.isEmpty() ?
1595 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
:
1596 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
);
1598 // No suggested password.
1599 ePassword
= (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
) ?
1600 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
:
1601 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED
;
1603 // Really, really bad things happen if we don't provide
1604 // the same user/password as was entered last time if
1605 // we failed to authenticate - infinite looping / flickering
1606 // madness etc. [ nice infrastructure ! ]
1607 static OUString aLastUserName
, aLastPassword
;
1608 if (in
->flags
& GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
)
1610 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1611 aUserName
= aLastUserName
;
1612 aPassword
= aLastPassword
;
1615 rtl::Reference
< ucbhelper::SimpleAuthenticationRequest
> xRequest
1616 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in
->uri
),
1617 aHostName
, eDomain
, aDomain
,
1618 eUserName
, aUserName
,
1619 ePassword
, aPassword
);
1621 xIH
->handle( xRequest
.get() );
1623 rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
1624 = xRequest
->getSelection();
1626 if ( xSelection
.is() ) {
1627 // Handler handled the request.
1628 uno::Reference
< task::XInteractionAbort
> xAbort(xSelection
.get(), uno::UNO_QUERY
);
1629 if ( !xAbort
.is() ) {
1630 const rtl::Reference
<
1631 ucbhelper::InteractionSupplyAuthentication
> & xSupp
1632 = xRequest
->getAuthenticationSupplier();
1634 OUString aNewDomain
, aNewUserName
, aNewPassword
;
1636 aNewUserName
= xSupp
->getUserName();
1637 if ( !aNewUserName
.isEmpty() )
1638 aUserName
= aNewUserName
;
1639 aNewDomain
= xSupp
->getRealm();
1640 if ( !aNewDomain
.isEmpty() )
1641 aDomain
= aNewDomain
;
1642 aNewPassword
= xSupp
->getPassword();
1643 if ( !aNewPassword
.isEmpty() )
1644 aPassword
= aNewPassword
;
1647 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
1648 aLastUserName
= aUserName
;
1649 aLastPassword
= aPassword
;
1652 out
->username
= OUStringToGnome( aUserName
);
1653 out
->domain
= OUStringToGnome( aDomain
);
1654 out
->password
= OUStringToGnome( aPassword
);
1655 out
->save_password
= xSupp
->getRememberPasswordMode();
1657 #if OSL_DEBUG_LEVEL > 1
1658 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password",
1659 out
->username
, out
->domain
, out
->password
,
1660 out
->save_password
? "save" : "don't save");
1664 out
->abort_auth
= TRUE
;
1667 out
->abort_auth
= TRUE
;
1671 vfs_authentication_old_callback (gconstpointer in_void
,
1675 gpointer callback_data
)
1678 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data
);
1680 const GnomeVFSModuleCallbackAuthenticationIn
*in
=
1681 (const GnomeVFSModuleCallbackAuthenticationIn
*) in_void
;
1682 GnomeVFSModuleCallbackAuthenticationOut
*out
=
1683 (GnomeVFSModuleCallbackAuthenticationOut
*) out_void
;
1685 g_return_if_fail (in
!= NULL
&& out
!= NULL
);
1686 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn
) == in_size
&&
1687 sizeof (GnomeVFSModuleCallbackAuthenticationOut
) == out_size
);
1689 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in
= {
1690 (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1691 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD
|
1692 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME
|
1693 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN
),
1694 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1695 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out
= { 0, 0, 0, 0, 0, 0, 0, 0 };
1697 // Map the old style input auth. data to the new style structure.
1698 if (in
->previous_attempt_failed
)
1699 mapped_in
.flags
= (GnomeVFSModuleCallbackFullAuthenticationFlags
)
1701 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED
);
1703 GnomeVFSURI
*pURI
= NULL
;
1704 // Urk - parse all this from the URL ...
1705 mapped_in
.uri
= in
->uri
;
1708 pURI
= gnome_vfs_uri_new( in
->uri
);
1709 mapped_in
.protocol
= (char *) gnome_vfs_uri_get_scheme (pURI
);
1710 mapped_in
.server
= (char *) gnome_vfs_uri_get_host_name (pURI
);
1711 mapped_in
.port
= gnome_vfs_uri_get_host_port (pURI
);
1712 mapped_in
.username
= (char *) gnome_vfs_uri_get_user_name (pURI
);
1714 mapped_in
.domain
= in
->realm
;
1715 mapped_in
.default_user
= mapped_in
.username
;
1716 mapped_in
.default_domain
= mapped_in
.domain
;
1718 vfs_authentication_callback ((gconstpointer
) &mapped_in
,
1720 (gpointer
) &mapped_out
,
1721 sizeof (mapped_out
),
1725 gnome_vfs_uri_unref (pURI
);
1727 // Map the new style auth. out data to the old style out structure.
1728 out
->username
= mapped_out
.username
;
1729 out
->password
= mapped_out
.password
;
1730 g_free (mapped_out
.domain
);
1731 g_free (mapped_out
.keyring
);
1736 auth_destroy (gpointer data
)
1738 task::XInteractionHandler
*xIH
;
1739 if( ( xIH
= ( task::XInteractionHandler
* )data
) )
1743 // This sucks, but gnome-vfs doesn't much like
1744 // repeated set / unsets - so we have to compensate.
1745 GPrivate
*auth_queue
= NULL
;
1747 void auth_queue_destroy( gpointer data
)
1750 GQueue
*vq
= (GQueue
*) data
;
1752 for (l
= vq
->head
; l
; l
= l
->next
)
1753 auth_destroy (l
->data
);
1759 refresh_auth( GQueue
*vq
)
1763 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
);
1764 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
);
1766 for (l
= vq
->head
; l
; l
= l
->next
) {
1768 gnome_vfs_module_callback_push
1769 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION
,
1770 vfs_authentication_old_callback
, l
->data
, NULL
);
1771 gnome_vfs_module_callback_push
1772 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION
,
1773 vfs_authentication_callback
, l
->data
, NULL
);
1779 gvfs::Authentication::Authentication(
1780 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1783 uno::Reference
< task::XInteractionHandler
> xIH
;
1786 xIH
= xEnv
->getInteractionHandler();
1791 if( !(vq
= (GQueue
*)g_private_get( auth_queue
) ) ) {
1793 g_private_set( auth_queue
, vq
);
1796 g_queue_push_head( vq
, (gpointer
) xIH
.get() );
1800 gvfs::Authentication::~Authentication()
1805 vq
= (GQueue
*)g_private_get( auth_queue
);
1807 data
= g_queue_pop_head( vq
);
1808 auth_destroy (data
);
1813 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */