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