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