xref: /trunk/main/ucb/source/ucp/gio/gio_content.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 
32 #include <osl/time.h>
33 
34 #include <osl/diagnose.h>
35 #include <osl/doublecheckedlocking.h>
36 
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/beans/PropertyAttribute.hpp>
39 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
40 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
41 #include <com/sun/star/io/XActiveDataSink.hpp>
42 #include <com/sun/star/io/XOutputStream.hpp>
43 #include <com/sun/star/lang/IllegalAccessException.hpp>
44 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
45 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
46 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
47 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
48 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
49 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
50 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
51 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
52 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
53 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
54 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
55 #include <com/sun/star/ucb/NameClash.hpp>
56 #include <com/sun/star/ucb/NameClashException.hpp>
57 #include <com/sun/star/ucb/OpenMode.hpp>
58 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
59 #include <com/sun/star/ucb/XCommandInfo.hpp>
60 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
61 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
62 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
63 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
64 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
65 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
66 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
67 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
68 #include <com/sun/star/ucb/NameClashException.hpp>
69 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
70 #include <com/sun/star/ucb/XContentCreator.hpp>
71 
72 #include <ucbhelper/contentidentifier.hxx>
73 #include <ucbhelper/propertyvalueset.hxx>
74 #include <ucbhelper/interactionrequest.hxx>
75 #include <ucbhelper/cancelcommandexecution.hxx>
76 
77 #include <osl/conditn.hxx>
78 
79 #include "gio_content.hxx"
80 #include "gio_provider.hxx"
81 #include "gio_resultset.hxx"
82 #include "gio_inputstream.hxx"
83 #include "gio_outputstream.hxx"
84 #include "gio_mount.hxx"
85 
86 #include <stdio.h>
87 
88 using namespace com::sun::star;
89 
90 namespace gio
91 {
92 
93 Content::Content(
94     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
95     ContentProvider* pProvider,
96     const uno::Reference< ucb::XContentIdentifier >& Identifier)
97         throw ( ucb::ContentCreationException )
98     : ContentImplHelper( rxSMgr, pProvider, Identifier ),
99       m_pProvider( pProvider ), mpFile (NULL), mpInfo( NULL ), mbTransient(false)
100 {
101 #ifdef DEBUG
102     fprintf(stderr, "New Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
103 #endif
104 }
105 
106 Content::Content(
107     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
108     ContentProvider* pProvider,
109     const uno::Reference< ucb::XContentIdentifier >& Identifier,
110     sal_Bool bIsFolder)
111         throw ( ucb::ContentCreationException )
112     : ContentImplHelper( rxSMgr, pProvider, Identifier ),
113       m_pProvider( pProvider ), mpFile (NULL), mpInfo( NULL ), mbTransient(true)
114 {
115 #ifdef DEBUG
116     fprintf(stderr, "Create Content ('%s')\n", rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
117 #endif
118     mpInfo = g_file_info_new();
119     g_file_info_set_file_type(mpInfo, bIsFolder ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR);
120 }
121 
122 Content::~Content()
123 {
124     if (mpInfo) g_object_unref(mpInfo);
125     if (mpFile) g_object_unref(mpFile);
126 }
127 
128 rtl::OUString Content::getParentURL()
129 {
130     rtl::OUString sURL;
131     if (GFile* pFile = g_file_get_parent(getGFile()))
132     {
133         char* pPath = g_file_get_uri(pFile);
134         g_object_unref(pFile);
135         sURL = rtl::OUString::createFromAscii(pPath);
136         g_free(pPath);
137     }
138     return sURL;
139 }
140 
141 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
142        throw( uno::RuntimeException )
143 {
144     //TODO
145     //stick a map from each CommandId to a new GCancellable and propogate
146     //it throughout the g_file_* calls
147 }
148 
149 rtl::OUString SAL_CALL Content::getContentType() throw( uno::RuntimeException )
150 {
151     return isFolder(uno::Reference< ucb::XCommandEnvironment >())
152         ? rtl::OUString::createFromAscii( GIO_FOLDER_TYPE )
153         : rtl::OUString::createFromAscii( GIO_FILE_TYPE );
154 }
155 
156 #define EXCEPT(aExcept) \
157 do { \
158     if (bThrow) throw aExcept;\
159     aRet = uno::makeAny( aExcept );\
160 } while(0)
161 
162 uno::Any convertToException(GError *pError, const uno::Reference< uno::XInterface >& rContext, bool bThrow)
163 {
164     uno::Any aRet;
165 
166     gint eCode = pError->code;
167     rtl::OUString sMessage(pError->message, strlen(pError->message), RTL_TEXTENCODING_UTF8);
168     g_error_free(pError);
169 
170     rtl::OUString sName;
171     rtl::OUString sHost;
172 
173     uno::Sequence< uno::Any > aArgs( 1 );
174     aArgs[ 0 ] <<= sName;
175 
176     switch (eCode)
177     {
178         case G_IO_ERROR_FAILED:
179             { io::IOException aExcept(sMessage, rContext);
180             EXCEPT(aExcept); }
181             break;
182         case G_IO_ERROR_NOT_MOUNTED:
183             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
184                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NOT_EXISTING_PATH, aArgs);
185             EXCEPT(aExcept); }
186             break;
187         case G_IO_ERROR_NOT_FOUND:
188             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
189                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NOT_EXISTING, aArgs);
190             EXCEPT(aExcept); }
191             break;
192         case G_IO_ERROR_EXISTS:
193             { ucb::NameClashException aExcept(sMessage, rContext,
194                 task::InteractionClassification_ERROR, sName);
195             EXCEPT(aExcept); }
196             break;
197         case G_IO_ERROR_INVALID_ARGUMENT:
198             { lang::IllegalArgumentException aExcept(sMessage, rContext, -1 );
199             EXCEPT(aExcept); }
200             break;
201         case G_IO_ERROR_PERMISSION_DENIED:
202             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
203                 task::InteractionClassification_ERROR, ucb::IOErrorCode_ACCESS_DENIED, aArgs);
204             EXCEPT(aExcept); }
205             break;
206         case G_IO_ERROR_IS_DIRECTORY:
207             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
208                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NO_FILE, aArgs);
209             EXCEPT(aExcept); }
210             break;
211         case G_IO_ERROR_NOT_REGULAR_FILE:
212             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
213                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NO_FILE, aArgs);
214             EXCEPT(aExcept); }
215             break;
216         case G_IO_ERROR_NOT_DIRECTORY:
217             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
218                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NO_DIRECTORY, aArgs);
219             EXCEPT(aExcept); }
220             break;
221         case G_IO_ERROR_FILENAME_TOO_LONG:
222             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
223                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NAME_TOO_LONG, aArgs);
224             EXCEPT(aExcept); }
225             break;
226         case G_IO_ERROR_PENDING:
227             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
228                 task::InteractionClassification_ERROR, ucb::IOErrorCode_PENDING, aArgs);
229             EXCEPT(aExcept); }
230             break;
231         case G_IO_ERROR_CLOSED:
232         case G_IO_ERROR_CANCELLED:
233         case G_IO_ERROR_TOO_MANY_LINKS:
234         case G_IO_ERROR_WRONG_ETAG:
235             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
236                 task::InteractionClassification_ERROR, ucb::IOErrorCode_GENERAL, aArgs);
237             EXCEPT(aExcept); }
238             break;
239         case G_IO_ERROR_NOT_SUPPORTED:
240         case G_IO_ERROR_CANT_CREATE_BACKUP:
241         case G_IO_ERROR_WOULD_MERGE:
242             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
243                 task::InteractionClassification_ERROR, ucb::IOErrorCode_NOT_SUPPORTED, aArgs);
244             EXCEPT(aExcept); }
245             break;
246         case G_IO_ERROR_NO_SPACE:
247             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
248                 task::InteractionClassification_ERROR, ucb::IOErrorCode_OUT_OF_DISK_SPACE, aArgs);
249             EXCEPT(aExcept); }
250             break;
251         case G_IO_ERROR_INVALID_FILENAME:
252             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
253                 task::InteractionClassification_ERROR, ucb::IOErrorCode_INVALID_CHARACTER, aArgs);
254             EXCEPT(aExcept); }
255             break;
256         case G_IO_ERROR_READ_ONLY:
257             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
258                 task::InteractionClassification_ERROR, ucb::IOErrorCode_WRITE_PROTECTED, aArgs);
259             EXCEPT(aExcept); }
260             break;
261         case G_IO_ERROR_TIMED_OUT:
262             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
263                 task::InteractionClassification_ERROR, ucb::IOErrorCode_DEVICE_NOT_READY, aArgs);
264             EXCEPT(aExcept); }
265             break;
266         case G_IO_ERROR_WOULD_RECURSE:
267             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
268                 task::InteractionClassification_ERROR, ucb::IOErrorCode_RECURSIVE, aArgs);
269             EXCEPT(aExcept); }
270             break;
271         case G_IO_ERROR_BUSY:
272         case G_IO_ERROR_WOULD_BLOCK:
273             { ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
274                 task::InteractionClassification_ERROR, ucb::IOErrorCode_LOCKING_VIOLATION, aArgs);
275             EXCEPT(aExcept); }
276             break;
277         case G_IO_ERROR_HOST_NOT_FOUND:
278             { ucb::InteractiveNetworkResolveNameException aExcept(sMessage, rContext,
279                 task::InteractionClassification_ERROR, sHost);
280               EXCEPT(aExcept);}
281             break;
282         default:
283         case G_IO_ERROR_ALREADY_MOUNTED:
284         case G_IO_ERROR_NOT_EMPTY:
285         case G_IO_ERROR_NOT_SYMBOLIC_LINK:
286         case G_IO_ERROR_NOT_MOUNTABLE_FILE:
287         case G_IO_ERROR_FAILED_HANDLED:
288             { ucb::InteractiveNetworkGeneralException aExcept(sMessage, rContext,
289                 task::InteractionClassification_ERROR);
290               EXCEPT(aExcept);}
291             break;
292     }
293     return aRet;
294 }
295 
296 uno::Any Content::mapGIOError( GError *pError )
297 {
298     if (!pError)
299         return getBadArgExcept();
300 
301     return convertToException(pError, static_cast< cppu::OWeakObject * >(this), false);
302 }
303 
304 uno::Any Content::getBadArgExcept()
305 {
306     return uno::makeAny( lang::IllegalArgumentException(
307         rtl::OUString::createFromAscii( "Wrong argument type!" ),
308         static_cast< cppu::OWeakObject * >( this ), -1) );
309 }
310 
311 class MountOperation
312 {
313     GMainLoop *mpLoop;
314     GMountOperation *mpAuthentication;
315     GError *mpError;
316     static void Completed(GObject *source, GAsyncResult *res, gpointer user_data);
317 public:
318     MountOperation(const uno::Reference< ucb::XCommandEnvironment >& xEnv);
319     ~MountOperation();
320     GError *Mount(GFile *pFile);
321 };
322 
323 MountOperation::MountOperation(const uno::Reference< ucb::XCommandEnvironment >& xEnv) : mpError(NULL)
324 {
325     mpLoop = g_main_loop_new(NULL, FALSE);
326     mpAuthentication = ooo_mount_operation_new(xEnv);
327 }
328 
329 void MountOperation::Completed(GObject *source, GAsyncResult *res, gpointer user_data)
330 {
331     MountOperation *pThis = (MountOperation*)user_data;
332     g_file_mount_enclosing_volume_finish(G_FILE(source), res, &(pThis->mpError));
333     g_main_loop_quit(pThis->mpLoop);
334 }
335 
336 GError *MountOperation::Mount(GFile *pFile)
337 {
338     g_file_mount_enclosing_volume(pFile, G_MOUNT_MOUNT_NONE, mpAuthentication, NULL, MountOperation::Completed, this);
339     g_main_loop_run(mpLoop);
340     return mpError;
341 }
342 
343 MountOperation::~MountOperation()
344 {
345     g_object_unref(mpAuthentication);
346     g_main_loop_unref(mpLoop);
347 }
348 
349 GFileInfo* Content::getGFileInfo(const uno::Reference< ucb::XCommandEnvironment >& xEnv, GError **ppError)
350 {
351     /*If we don't have it already, and we're not a "pre-creation" content then query for the info"*/
352     if (!mpInfo && !mbTransient)
353     {
354         if (!(mpInfo = g_file_query_info(getGFile(), "*", G_FILE_QUERY_INFO_NONE, NULL, ppError)))
355         {
356             //Try and mount if unmounted
357             if (ppError && (*ppError)->code == G_IO_ERROR_NOT_MOUNTED)
358             {
359                 g_error_free(*ppError);
360 
361                 MountOperation aMounter(xEnv);
362                 *ppError = aMounter.Mount(getGFile());
363 
364                 //No Mount error, reattempt query
365         if (!*ppError)
366                     mpInfo = g_file_query_info(getGFile(), "*", G_FILE_QUERY_INFO_NONE, NULL, ppError);
367             }
368         }
369     }
370     return mpInfo;
371 }
372 
373 GFile* Content::getGFile()
374 {
375     if (!mpFile)
376         mpFile = g_file_new_for_uri(rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
377     return mpFile;
378 }
379 
380 bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv)
381 {
382     GFileInfo *pInfo = getGFileInfo(xEnv);
383     return pInfo && (g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY);
384 }
385 
386 static util::DateTime getDateFromUnix (time_t t)
387 {
388     TimeValue tv;
389     tv.Nanosec = 0;
390     tv.Seconds = t;
391     oslDateTime dt;
392 
393     if ( osl_getDateTimeFromTimeValue( &tv, &dt ) )
394         return util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours,
395                                dt.Day, dt.Month, dt.Year);
396     else
397         return util::DateTime();
398 }
399 
400 uno::Reference< sdbc::XRow > Content::getPropertyValuesFromGFileInfo(GFileInfo *pInfo,
401     const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
402     const uno::Reference< ucb::XCommandEnvironment > & xEnv,
403     const uno::Sequence< beans::Property >& rProperties)
404 {
405     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( rSMgr );
406 
407     sal_Int32 nProps;
408     const beans::Property* pProps;
409 
410     nProps = rProperties.getLength();
411     pProps = rProperties.getConstArray();
412 
413     for( sal_Int32 n = 0; n < nProps; ++n )
414     {
415         const beans::Property& rProp = pProps[ n ];
416 
417         if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
418         {
419             if (g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE))
420                 xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_REGULAR ||
421                                                g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_UNKNOWN ) );
422             else
423                 xRow->appendVoid( rProp );
424         }
425         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
426         {
427             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) )
428                 xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_DIRECTORY ));
429             else
430                 xRow->appendVoid( rProp );
431         }
432         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
433         {
434             if (g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
435             {
436                 const char *pName = g_file_info_get_display_name(pInfo);
437                 xRow->appendString( rProp, rtl::OUString(pName, strlen(pName), RTL_TEXTENCODING_UTF8) );
438             }
439             else
440                 xRow->appendVoid( rProp );
441         }
442         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) )
443         {
444             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE ) )
445                 xRow->appendBoolean( rProp, !g_file_info_get_attribute_boolean( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE) );
446             else
447                 xRow->appendVoid( rProp );
448         }
449         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
450         {
451             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CREATED ) )
452                 xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CREATED)) );
453             else
454                 xRow->appendVoid( rProp );
455         }
456         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
457         {
458             if( g_file_info_has_attribute( pInfo,  G_FILE_ATTRIBUTE_TIME_CHANGED ) )
459                 xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED)) );
460             else
461                 xRow->appendVoid( rProp );
462         }
463         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
464         {
465             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_SIZE) )
466                 xRow->appendLong( rProp, ( g_file_info_get_size( pInfo ) ));
467             else
468                 xRow->appendVoid( rProp );
469         }
470         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsVolume" ) ) )
471         {
472             //What do we use this for ?
473             xRow->appendBoolean( rProp, sal_False );
474         }
475         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsCompactDisc" ) ) )
476         {
477             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT ) )
478                 xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT) );
479             else
480                 xRow->appendVoid( rProp );
481         }
482         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsRemoveable" ) ) )
483         {
484             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) )
485                 xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) );
486             else
487                 xRow->appendVoid( rProp );
488         }
489         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFloppy" ) ) )
490         {
491             xRow->appendBoolean( rProp, sal_False );
492         }
493         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsHidden" ) ) )
494         {
495             if( g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) )
496                 xRow->appendBoolean( rProp, ( g_file_info_get_is_hidden ( pInfo ) ) );
497             else
498                 xRow->appendVoid( rProp );
499         }
500         else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
501         {
502             xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
503         }
504 #ifdef DEBUG
505         else
506         {
507             fprintf(stderr, "Looking for unsupported property %s\n",
508                 rtl::OUStringToOString(rProp.Name, RTL_TEXTENCODING_UTF8).getStr());
509         }
510 #endif
511     }
512 
513     return uno::Reference< sdbc::XRow >( xRow.get() );
514 }
515 
516 uno::Reference< sdbc::XRow > Content::getPropertyValues(
517                 const uno::Sequence< beans::Property >& rProperties,
518                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
519 {
520     GError *pError = NULL;
521     GFileInfo *pInfo = getGFileInfo(xEnv, &pError);
522     if (!pInfo)
523         ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
524 
525     return getPropertyValuesFromGFileInfo(pInfo, m_xSMgr, xEnv, rProperties);
526 }
527 
528 static lang::IllegalAccessException
529 getReadOnlyException( const uno::Reference< uno::XInterface >& rContext )
530 {
531     return lang::IllegalAccessException ( rtl::OUString::createFromAscii( "Property is read-only!" ), rContext );
532 }
533 
534 void Content::queryChildren( ContentRefList& rChildren )
535 {
536     // Obtain a list with a snapshot of all currently instanciated contents
537     // from provider and extract the contents which are direct children
538     // of this content.
539 
540     ucbhelper::ContentRefList aAllContents;
541     m_xProvider->queryExistingContents( aAllContents );
542 
543     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
544     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
545 
546     if ( nURLPos != ( aURL.getLength() - 1 ) )
547         aURL += rtl::OUString::createFromAscii( "/" );
548 
549     sal_Int32 nLen = aURL.getLength();
550 
551     ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
552     ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
553 
554     while ( it != end )
555     {
556         ucbhelper::ContentImplHelperRef xChild = (*it);
557         rtl::OUString aChildURL = xChild->getIdentifier()->getContentIdentifier();
558 
559         // Is aURL a prefix of aChildURL?
560         if ( ( aChildURL.getLength() > nLen ) && ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
561         {
562             sal_Int32 nPos = nLen;
563             nPos = aChildURL.indexOf( '/', nPos );
564 
565             if ( ( nPos == -1 ) || ( nPos == ( aChildURL.getLength() - 1 ) ) )
566             {
567                 // No further slashes / only a final slash. It's a child!
568                 rChildren.push_back( ::gio::Content::ContentRef (static_cast< ::gio::Content * >(xChild.get() ) ) );
569             }
570         }
571         ++it;
572     }
573 }
574 
575 sal_Bool Content::exchangeIdentity( const uno::Reference< ucb::XContentIdentifier >& xNewId )
576 {
577     if ( !xNewId.is() )
578         return sal_False;
579 
580     uno::Reference< ucb::XContent > xThis = this;
581 
582     if ( mbTransient )
583     {
584         m_xIdentifier = xNewId;
585         return sal_False;
586     }
587 
588     rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
589 
590     // Exchange own identitity.
591     if ( exchange( xNewId ) )
592     {
593         // Process instanciated children...
594         ContentRefList aChildren;
595         queryChildren( aChildren );
596 
597         ContentRefList::const_iterator it  = aChildren.begin();
598         ContentRefList::const_iterator end = aChildren.end();
599 
600         while ( it != end )
601         {
602             ContentRef xChild = (*it);
603 
604             // Create new content identifier for the child...
605             uno::Reference< ucb::XContentIdentifier > xOldChildId = xChild->getIdentifier();
606             rtl::OUString aOldChildURL = xOldChildId->getContentIdentifier();
607             rtl::OUString aNewChildURL = aOldChildURL.replaceAt(
608                 0, aOldURL.getLength(), xNewId->getContentIdentifier() );
609 
610             uno::Reference< ucb::XContentIdentifier > xNewChildId
611                 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewChildURL );
612 
613             if ( !xChild->exchangeIdentity( xNewChildId ) )
614                 return sal_False;
615 
616             ++it;
617          }
618          return sal_True;
619     }
620 
621     return sal_False;
622 }
623 
624 uno::Sequence< uno::Any > Content::setPropertyValues(
625     const uno::Sequence< beans::PropertyValue >& rValues,
626     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
627 {
628     GError *pError=NULL;
629     GFileInfo *pNewInfo=NULL;
630     GFileInfo *pInfo = getGFileInfo(xEnv, &pError);
631     if (pInfo)
632         pNewInfo = g_file_info_dup(pInfo);
633     else
634     {
635         if (!mbTransient)
636             ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
637         else
638         {
639             if (pError)
640                 g_error_free(pError);
641             pNewInfo = g_file_info_new();
642         }
643     }
644 
645     sal_Int32 nCount = rValues.getLength();
646 
647     beans::PropertyChangeEvent aEvent;
648     aEvent.Source = static_cast< cppu::OWeakObject * >( this );
649     aEvent.Further = sal_False;
650     aEvent.PropertyHandle = -1;
651 
652     sal_Int32 nChanged = 0, nTitlePos = -1;
653     const char *newName = NULL;
654     uno::Sequence< beans::PropertyChangeEvent > aChanges(nCount);
655 
656     uno::Sequence< uno::Any > aRet( nCount );
657     const beans::PropertyValue* pValues = rValues.getConstArray();
658     for ( sal_Int32 n = 0; n < nCount; ++n )
659     {
660         const beans::PropertyValue& rValue = pValues[ n ];
661 #ifdef DEBUG
662         g_warning("Set prop '%s'", rtl::OUStringToOString(rValue.Name, RTL_TEXTENCODING_UTF8).getStr());
663 #endif
664         if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ||
665              rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ||
666              rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ||
667              rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ||
668              rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ||
669              rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
670         {
671             aRet[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
672         }
673         else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
674         {
675             rtl::OUString aNewTitle;
676             if (!( rValue.Value >>= aNewTitle ))
677             {
678                 aRet[ n ] <<= beans::IllegalTypeException
679                     ( rtl::OUString::createFromAscii( "Property value has wrong type!" ),
680                       static_cast< cppu::OWeakObject * >( this ) );
681                 continue;
682             }
683 
684             if ( aNewTitle.getLength() <= 0 )
685             {
686                 aRet[ n ] <<= lang::IllegalArgumentException
687                     ( rtl::OUString::createFromAscii( "Empty title not allowed!" ),
688                       static_cast< cppu::OWeakObject * >( this ), -1 );
689                 continue;
690 
691             }
692 
693             rtl::OString sNewTitle = OUStringToOString(aNewTitle, RTL_TEXTENCODING_UTF8);
694             newName = sNewTitle.getStr();
695             const char *oldName = g_file_info_get_name( pInfo);
696 
697             if (!newName || !oldName || strcmp(newName, oldName))
698             {
699 #ifdef DEBUG
700                 g_warning ("Set new name to '%s'", newName);
701 #endif
702 
703                 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
704                 if (oldName)
705                     aEvent.OldValue = uno::makeAny(rtl::OUString(oldName, strlen(oldName), RTL_TEXTENCODING_UTF8));
706                 aEvent.NewValue = uno::makeAny(aNewTitle);
707                 aChanges.getArray()[ nChanged ] = aEvent;
708                 nTitlePos = nChanged++;
709 
710                 g_file_info_set_name(pNewInfo, newName);
711             }
712         }
713         else
714         {
715 #ifdef DEBUG
716             fprintf(stderr, "Unknown property %s\n", rtl::OUStringToOString(rValue.Name, RTL_TEXTENCODING_UTF8).getStr());
717 #endif
718             aRet[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
719             //TODO
720         }
721     }
722 
723     if (nChanged)
724     {
725         bool bOk = true;
726         if (!mbTransient)
727         {
728             if ((bOk = doSetFileInfo(pNewInfo)))
729             {
730                 for (sal_Int32 i = 0; i < nChanged; ++i)
731                     aRet[ i ] <<= getBadArgExcept();
732             }
733         }
734 
735         if (bOk)
736         {
737             if (nTitlePos > -1)
738             {
739                 rtl::OUString aNewURL = getParentURL();
740                 aNewURL += rtl::OUString( newName, strlen(newName), RTL_TEXTENCODING_UTF8 );
741                 uno::Reference< ucb::XContentIdentifier > xNewId
742                     = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewURL );
743 
744                 if (!exchangeIdentity( xNewId ) )
745                 {
746                     aRet[ nTitlePos ] <<= uno::Exception
747                         ( rtl::OUString::createFromAscii( "Exchange failed!" ),
748                           static_cast< cppu::OWeakObject * >( this ) );
749                 }
750             }
751 
752             if (!mbTransient) //Discard and refetch
753             {
754                 g_object_unref(mpInfo);
755                 mpInfo = NULL;
756             }
757 
758             if (mpInfo)
759             {
760                 g_file_info_copy_into(pNewInfo, mpInfo);
761                 g_object_unref(pNewInfo);
762             }
763             else
764                 mpInfo = pNewInfo;
765 
766             if (mpFile) //Discard and refetch
767             {
768                 g_object_unref(mpFile);
769                 mpFile = NULL;
770             }
771         }
772 
773         aChanges.realloc( nChanged );
774         notifyPropertiesChange( aChanges );
775     }
776 
777     return aRet;
778 }
779 
780 bool Content::doSetFileInfo(GFileInfo *pNewInfo)
781 {
782     g_assert (!mbTransient);
783 
784     bool bOk = true;
785     GFile *pFile = getGFile();
786     if(!g_file_set_attributes_from_info(pFile, pNewInfo, G_FILE_QUERY_INFO_NONE, NULL, NULL))
787         bOk = false;
788     return bOk;
789 }
790 
791 const int TRANSFER_BUFFER_SIZE = 65536;
792 
793 void Content::copyData( uno::Reference< io::XInputStream > xIn,
794     uno::Reference< io::XOutputStream > xOut )
795 {
796     uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
797 
798     g_return_if_fail( xIn.is() && xOut.is() );
799 
800     while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
801         xOut->writeBytes( theData );
802 
803     xOut->closeOutput();
804 }
805 
806 sal_Bool Content::feedSink( uno::Reference< uno::XInterface > xSink,
807     const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
808 {
809     if ( !xSink.is() )
810         return sal_False;
811 
812     uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY );
813     uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY );
814 
815     if ( !xOut.is() && !xDataSink.is() )
816         return sal_False;
817 
818     GError *pError=NULL;
819     GFileInputStream *pStream = g_file_read(getGFile(), NULL, &pError);
820     if (!pStream)
821        convertToException(pError, static_cast< cppu::OWeakObject * >(this));
822 
823     uno::Reference< io::XInputStream > xIn = new ::gio::InputStream(pStream);
824     if ( !xIn.is() )
825         return sal_False;
826 
827     if ( xOut.is() )
828         copyData( xIn, xOut );
829 
830     if ( xDataSink.is() )
831         xDataSink->setInputStream( xIn );
832 
833     return sal_True;
834 }
835 
836 uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand,
837     const uno::Reference< ucb::XCommandEnvironment > & xEnv )
838     throw( uno::Exception )
839 {
840     bool bIsFolder = isFolder(xEnv);
841 
842     if (!g_file_query_exists(getGFile(), NULL))
843     {
844         uno::Sequence< uno::Any > aArgs( 1 );
845         aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
846         uno::Any aErr = uno::makeAny(
847             ucb::InteractiveAugmentedIOException(rtl::OUString(), static_cast< cppu::OWeakObject * >( this ),
848                 task::InteractionClassification_ERROR,
849                 bIsFolder ? ucb::IOErrorCode_NOT_EXISTING_PATH : ucb::IOErrorCode_NOT_EXISTING, aArgs)
850         );
851 
852         ucbhelper::cancelCommandExecution(aErr, xEnv);
853     }
854 
855     uno::Any aRet;
856 
857     sal_Bool bOpenFolder = (
858         ( rOpenCommand.Mode == ucb::OpenMode::ALL ) ||
859         ( rOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
860         ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENTS )
861      );
862 
863     if ( bOpenFolder && bIsFolder )
864     {
865         uno::Reference< ucb::XDynamicResultSet > xSet
866             = new DynamicResultSet(m_xSMgr, this, rOpenCommand, xEnv );
867         aRet <<= xSet;
868     }
869     else if ( rOpenCommand.Sink.is() )
870     {
871         if (
872             ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
873             ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
874            )
875         {
876             ucbhelper::cancelCommandExecution(
877                 uno::makeAny ( ucb::UnsupportedOpenModeException
878                     ( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ),
879                       sal_Int16( rOpenCommand.Mode ) ) ),
880                     xEnv );
881         }
882 
883         if ( !feedSink( rOpenCommand.Sink, xEnv ) )
884         {
885             // Note: rOpenCommand.Sink may contain an XStream
886             //       implementation. Support for this type of
887             //       sink is optional...
888 #ifdef DEBUG
889             g_warning ("Failed to load data from '%s'",
890                 rtl::OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
891 #endif
892 
893             ucbhelper::cancelCommandExecution(
894                 uno::makeAny (ucb::UnsupportedDataSinkException
895                     ( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ),
896                       rOpenCommand.Sink ) ),
897                     xEnv );
898         }
899     }
900     else
901         g_warning ("Open falling through ...");
902     return aRet;
903 }
904 
905 uno::Any SAL_CALL Content::execute(
906         const ucb::Command& aCommand,
907         sal_Int32 /*CommandId*/,
908         const uno::Reference< ucb::XCommandEnvironment >& xEnv )
909     throw( uno::Exception,
910            ucb::CommandAbortedException,
911            uno::RuntimeException )
912 {
913 #ifdef DEBUG
914     fprintf(stderr, "Content::execute %s\n", rtl::OUStringToOString(aCommand.Name, RTL_TEXTENCODING_UTF8).getStr());
915 #endif
916     uno::Any aRet;
917 
918     if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ))
919     {
920         uno::Sequence< beans::Property > Properties;
921         if ( !( aCommand.Argument >>= Properties ) )
922             ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
923         aRet <<= getPropertyValues( Properties, xEnv );
924     }
925     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ))
926         aRet <<= getPropertySetInfo( xEnv, sal_False );
927     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ))
928         aRet <<= getCommandInfo( xEnv, sal_False );
929     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "open" ) ))
930     {
931         ucb::OpenCommandArgument2 aOpenCommand;
932         if ( !( aCommand.Argument >>= aOpenCommand ) )
933             ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
934         aRet = open( aOpenCommand, xEnv );
935     }
936     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "transfer" ) ))
937     {
938         ucb::TransferInfo transferArgs;
939         if ( !( aCommand.Argument >>= transferArgs ) )
940             ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
941         transfer( transferArgs, xEnv );
942     }
943     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ))
944     {
945         uno::Sequence< beans::PropertyValue > aProperties;
946         if ( !( aCommand.Argument >>= aProperties ) || !aProperties.getLength() )
947             ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
948         aRet <<= setPropertyValues( aProperties, xEnv );
949     }
950     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) )
951              && isFolder( xEnv ) )
952     {
953         ucb::ContentInfo arg;
954         if ( !( aCommand.Argument >>= arg ) )
955                 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
956         aRet <<= createNewContent( arg );
957     }
958     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "insert" ) ))
959     {
960         ucb::InsertCommandArgument arg;
961         if ( !( aCommand.Argument >>= arg ) )
962                 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
963         insert( arg.Data, arg.ReplaceExisting, xEnv );
964     }
965     else if (aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ))
966     {
967         sal_Bool bDeletePhysical = sal_False;
968         aCommand.Argument >>= bDeletePhysical;
969 
970         //If no delete physical, try and trashcan it, if that doesn't work go
971         //ahead and try and delete it anyway
972         if (!bDeletePhysical && !g_file_trash(getGFile(), NULL, NULL))
973                 bDeletePhysical = true;
974 
975         if (bDeletePhysical)
976         {
977             GError *pError = NULL;
978             if (!g_file_delete( getGFile(), NULL, &pError))
979                 ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
980         }
981 
982         destroy( bDeletePhysical );
983     }
984     else
985     {
986 #ifdef DEBUG
987         fprintf(stderr, "UNKNOWN COMMAND\n");
988         //TODO
989 #endif
990 
991         ucbhelper::cancelCommandExecution
992             ( uno::makeAny( ucb::UnsupportedCommandException
993               ( rtl::OUString(),
994                 static_cast< cppu::OWeakObject * >( this ) ) ),
995               xEnv );
996     }
997 
998     return aRet;
999 }
1000 
1001 void Content::destroy( sal_Bool bDeletePhysical )
1002     throw( uno::Exception )
1003 {
1004     uno::Reference< ucb::XContent > xThis = this;
1005 
1006     deleted();
1007 
1008     ::gio::Content::ContentRefList aChildren;
1009     queryChildren( aChildren );
1010 
1011     ContentRefList::const_iterator it  = aChildren.begin();
1012     ContentRefList::const_iterator end = aChildren.end();
1013 
1014     while ( it != end )
1015     {
1016         (*it)->destroy( bDeletePhysical );
1017         ++it;
1018     }
1019 }
1020 
1021 void Content::insert(const uno::Reference< io::XInputStream > &xInputStream,
1022     sal_Bool bReplaceExisting, const uno::Reference< ucb::XCommandEnvironment > &xEnv )
1023         throw( uno::Exception )
1024 {
1025     GError *pError = NULL;
1026     GFileInfo *pInfo = getGFileInfo(xEnv);
1027 
1028     if ( g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
1029          g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY )
1030     {
1031 #ifdef DEBUG
1032         g_warning ("Make directory");
1033 #endif
1034         if( !g_file_make_directory( getGFile(), NULL, &pError))
1035             ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1036         return;
1037     }
1038 
1039     if ( !xInputStream.is() )
1040     {
1041         ucbhelper::cancelCommandExecution( uno::makeAny
1042             ( ucb::MissingInputStreamException
1043               ( rtl::OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
1044             xEnv );
1045     }
1046 
1047     GFileOutputStream* pOutStream = NULL;
1048     if ( bReplaceExisting )
1049     {
1050         if (!(pOutStream = g_file_replace(getGFile(), NULL, false, G_FILE_CREATE_PRIVATE, NULL, &pError)))
1051             ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1052     }
1053     else
1054     {
1055         if (!(pOutStream = g_file_create (getGFile(), G_FILE_CREATE_PRIVATE, NULL, &pError)))
1056             ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1057     }
1058 
1059     uno::Reference < io::XOutputStream > xOutput = new ::gio::OutputStream(pOutStream);
1060     copyData( xInputStream, xOutput );
1061 
1062     if (mbTransient)
1063     {
1064         mbTransient = sal_False;
1065         inserted();
1066     }
1067 }
1068 
1069 void Content::transfer( const ucb::TransferInfo& aTransferInfo, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1070     throw( uno::Exception )
1071 {
1072     rtl::OUString sDest = m_xIdentifier->getContentIdentifier();
1073     if (aTransferInfo.NewTitle.getLength())
1074         sDest += aTransferInfo.NewTitle;
1075     else
1076         sDest += rtl::OUString::createFromAscii(g_file_get_basename(getGFile()));
1077 
1078     GFile *pDest = g_file_new_for_uri(rtl::OUStringToOString(sDest, RTL_TEXTENCODING_UTF8).getStr());
1079     GFile *pSource = g_file_new_for_uri(rtl::OUStringToOString(aTransferInfo.SourceURL, RTL_TEXTENCODING_UTF8).getStr());
1080 
1081     gboolean bSuccess = false;
1082     GError *pError = NULL;
1083     if (aTransferInfo.MoveData)
1084         bSuccess = g_file_move(pSource, pDest, G_FILE_COPY_OVERWRITE, NULL, NULL, 0, &pError);
1085     else
1086         bSuccess = g_file_copy(pSource, pDest, G_FILE_COPY_OVERWRITE, NULL, NULL, 0, &pError);
1087     g_object_unref(pSource);
1088     g_object_unref(pDest);
1089     if (!bSuccess)
1090         ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
1091 }
1092 
1093 uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo(
1094     const uno::Reference< ucb::XCommandEnvironment >& xEnv)
1095             throw( uno::RuntimeException )
1096 {
1097     if ( isFolder( xEnv ) )
1098     {
1099         uno::Sequence< ucb::ContentInfo > seq(2);
1100 
1101         // Minimum set of props we really need
1102         uno::Sequence< beans::Property > props( 1 );
1103         props[0] = beans::Property(
1104             rtl::OUString::createFromAscii( "Title" ),
1105             -1,
1106             getCppuType( static_cast< rtl::OUString* >( 0 ) ),
1107             beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND );
1108 
1109         // file
1110         seq[0].Type       = rtl::OUString::createFromAscii( GIO_FILE_TYPE );
1111         seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
1112                               ucb::ContentInfoAttribute::KIND_DOCUMENT );
1113         seq[0].Properties = props;
1114 
1115         // folder
1116         seq[1].Type       = rtl::OUString::createFromAscii( GIO_FOLDER_TYPE );
1117         seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1118         seq[1].Properties = props;
1119 
1120         return seq;
1121     }
1122     else
1123     {
1124         return uno::Sequence< ucb::ContentInfo >();
1125     }
1126 }
1127 
1128 uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1129             throw( uno::RuntimeException )
1130 {
1131     return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() );
1132 }
1133 
1134 uno::Reference< ucb::XContent >
1135     SAL_CALL Content::createNewContent( const ucb::ContentInfo& Info )
1136         throw( uno::RuntimeException )
1137 {
1138     bool create_document;
1139     const char *name;
1140 
1141     if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GIO_FILE_TYPE ) ) )
1142         create_document = true;
1143     else if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GIO_FOLDER_TYPE ) ) )
1144         create_document = false;
1145     else
1146     {
1147 #ifdef DEBUG
1148         g_warning( "Failed to create new content '%s'", rtl::OUStringToOString(Info.Type,
1149             RTL_TEXTENCODING_UTF8).getStr() );
1150 #endif
1151         return uno::Reference< ucb::XContent >();
1152     }
1153 
1154 #ifdef DEBUG
1155     g_warning( "createNewContent (%d)", (int) create_document );
1156 #endif
1157 
1158     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1159 
1160     if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1161             aURL += rtl::OUString::createFromAscii( "/" );
1162 
1163     name = create_document ? "[New_Content]" : "[New_Collection]";
1164     aURL += rtl::OUString::createFromAscii( name );
1165 
1166     uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(m_xSMgr, aURL));
1167 
1168     try
1169     {
1170         return new ::gio::Content( m_xSMgr, m_pProvider, xId, !create_document );
1171     } catch ( ucb::ContentCreationException & )
1172     {
1173             return uno::Reference< ucb::XContent >();
1174     }
1175 }
1176 
1177 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
1178     throw( uno::RuntimeException )
1179 {
1180     if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
1181     {
1182         static cppu::OTypeCollection aFolderCollection
1183             (CPPU_TYPE_REF( lang::XTypeProvider ),
1184              CPPU_TYPE_REF( lang::XServiceInfo ),
1185              CPPU_TYPE_REF( lang::XComponent ),
1186              CPPU_TYPE_REF( ucb::XContent ),
1187              CPPU_TYPE_REF( ucb::XCommandProcessor ),
1188              CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1189              CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1190              CPPU_TYPE_REF( beans::XPropertyContainer ),
1191              CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1192              CPPU_TYPE_REF( container::XChild ),
1193              CPPU_TYPE_REF( ucb::XContentCreator ) );
1194         return aFolderCollection.getTypes();
1195     }
1196     else
1197     {
1198         static cppu::OTypeCollection aFileCollection
1199             (CPPU_TYPE_REF( lang::XTypeProvider ),
1200              CPPU_TYPE_REF( lang::XServiceInfo ),
1201              CPPU_TYPE_REF( lang::XComponent ),
1202              CPPU_TYPE_REF( ucb::XContent ),
1203              CPPU_TYPE_REF( ucb::XCommandProcessor ),
1204              CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1205              CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1206              CPPU_TYPE_REF( beans::XPropertyContainer ),
1207              CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1208              CPPU_TYPE_REF( container::XChild ) );
1209 
1210         return aFileCollection.getTypes();
1211     }
1212 }
1213 
1214 uno::Sequence< beans::Property > Content::getProperties(
1215     const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ )
1216 {
1217     static const beans::Property aGenericProperties[] =
1218     {
1219         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
1220             -1, getCppuBooleanType(),
1221             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1222         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
1223             -1, getCppuBooleanType(),
1224             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1225         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1226             -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1227             beans::PropertyAttribute::BOUND ),
1228         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ),
1229             -1, getCppuBooleanType(),
1230             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1231         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ),
1232             -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1233             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1234         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ),
1235             -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1236             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1237         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ),
1238             -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ),
1239             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1240         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsVolume" ) ),
1241             -1, getCppuBooleanType(),
1242             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1243         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsCompactDisc" ) ),
1244             -1, getCppuBooleanType(),
1245             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1246         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsRemoveable" ) ),
1247             -1, getCppuBooleanType(),
1248             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1249         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ),
1250             -1, getCppuBooleanType(),
1251             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1252         beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
1253             -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1254             beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY )
1255     };
1256 
1257     const int nProps = sizeof (aGenericProperties) / sizeof (aGenericProperties[0]);
1258     return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
1259 }
1260 
1261 uno::Sequence< ucb::CommandInfo > Content::getCommands( const uno::Reference< ucb::XCommandEnvironment > & xEnv)
1262 {
1263     static ucb::CommandInfo aCommandInfoTable[] =
1264     {
1265         // Required commands
1266         ucb::CommandInfo
1267         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ),
1268           -1, getCppuVoidType() ),
1269         ucb::CommandInfo
1270         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ),
1271           -1, getCppuVoidType() ),
1272         ucb::CommandInfo
1273         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ),
1274           -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
1275         ucb::CommandInfo
1276         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
1277           -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
1278 
1279         // Optional standard commands
1280         ucb::CommandInfo
1281         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ),
1282           -1, getCppuBooleanType() ),
1283         ucb::CommandInfo
1284         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ),
1285           -1, getCppuType( static_cast<ucb::InsertCommandArgument * >( 0 ) ) ),
1286         ucb::CommandInfo
1287         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ),
1288           -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
1289 
1290         // Folder Only, omitted if not a folder
1291         ucb::CommandInfo
1292         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ),
1293           -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1294         ucb::CommandInfo
1295         ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "createNewContent" ) ),
1296           -1, getCppuType( static_cast<ucb::ContentInfo * >( 0 ) ) )
1297     };
1298 
1299     const int nProps = sizeof (aCommandInfoTable) / sizeof (aCommandInfoTable[0]);
1300     return uno::Sequence< ucb::CommandInfo >(aCommandInfoTable, isFolder(xEnv) ? nProps : nProps - 2);
1301 }
1302 
1303 XTYPEPROVIDER_COMMON_IMPL( Content );
1304 
1305 void SAL_CALL Content::acquire() throw()
1306 {
1307     ContentImplHelper::acquire();
1308 }
1309 
1310 void SAL_CALL Content::release() throw()
1311 {
1312     ContentImplHelper::release();
1313 }
1314 
1315 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException )
1316 {
1317     uno::Any aRet = cppu::queryInterface( rType, static_cast< ucb::XContentCreator * >( this ) );
1318     return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1319 }
1320 
1321 rtl::OUString SAL_CALL Content::getImplementationName() throw( uno::RuntimeException )
1322 {
1323        return rtl::OUString::createFromAscii("com.sun.star.comp.GIOContent" );
1324 }
1325 
1326 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
1327        throw( uno::RuntimeException )
1328 {
1329        uno::Sequence< rtl::OUString > aSNS( 1 );
1330        aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii("com.sun.star.ucb.GIOContent" );
1331        return aSNS;
1332 }
1333 
1334 }
1335