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