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