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