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