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