Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/ucb/source/ucp/tdoc/tdoc_content.cxx
Line
Count
Source
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
21
/**************************************************************************
22
                                TODO
23
 **************************************************************************
24
25
 *************************************************************************/
26
27
#include <sal/config.h>
28
29
#include <string_view>
30
31
#include <o3tl/string_view.hxx>
32
#include <comphelper/diagnose_ex.hxx>
33
#include <rtl/ustrbuf.hxx>
34
#include <com/sun/star/beans/IllegalTypeException.hpp>
35
#include <com/sun/star/beans/PropertyAttribute.hpp>
36
#include <com/sun/star/beans/XPropertySet.hpp>
37
#include <com/sun/star/embed/InvalidStorageException.hpp>
38
#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
39
#include <com/sun/star/embed/XTransactedObject.hpp>
40
#include <com/sun/star/io/BufferSizeExceededException.hpp>
41
#include <com/sun/star/io/IOException.hpp>
42
#include <com/sun/star/io/NotConnectedException.hpp>
43
#include <com/sun/star/io/XActiveDataSink.hpp>
44
#include <com/sun/star/io/XActiveDataStreamer.hpp>
45
#include <com/sun/star/lang/IllegalAccessException.hpp>
46
#include <com/sun/star/packages/WrongPasswordException.hpp>
47
#include <com/sun/star/task/DocumentPasswordRequest.hpp>
48
#include <com/sun/star/task/XInteractionPassword.hpp>
49
#include <com/sun/star/ucb/CommandFailedException.hpp>
50
#include <com/sun/star/ucb/ContentAction.hpp>
51
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
52
#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
53
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
54
#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
55
#include <com/sun/star/ucb/IOErrorCode.hpp>
56
#include <com/sun/star/ucb/MissingInputStreamException.hpp>
57
#include <com/sun/star/ucb/NameClash.hpp>
58
#include <com/sun/star/ucb/NameClashException.hpp>
59
#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
60
#include <com/sun/star/ucb/OpenMode.hpp>
61
#include <com/sun/star/ucb/TransferInfo.hpp>
62
#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
63
#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
64
#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
65
#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
66
#include <com/sun/star/ucb/XCommandInfo.hpp>
67
#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
68
69
#include <comphelper/propertysequence.hxx>
70
#include <cppuhelper/queryinterface.hxx>
71
#include <ucbhelper/cancelcommandexecution.hxx>
72
#include <ucbhelper/contentidentifier.hxx>
73
#include <ucbhelper/propertyvalueset.hxx>
74
#include <ucbhelper/macros.hxx>
75
#include <utility>
76
77
#include "tdoc_content.hxx"
78
#include "tdoc_resultset.hxx"
79
#include "tdoc_passwordrequest.hxx"
80
81
#include "../inc/urihelper.hxx"
82
83
using namespace com::sun::star;
84
using namespace tdoc_ucp;
85
86
87
static ContentType lcl_getContentType( std::u16string_view rType )
88
0
{
89
0
    if ( rType == TDOC_ROOT_CONTENT_TYPE )
90
0
        return ROOT;
91
0
    else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
92
0
        return DOCUMENT;
93
0
    else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
94
0
        return FOLDER;
95
0
    else if ( rType == TDOC_STREAM_CONTENT_TYPE )
96
0
        return STREAM;
97
0
    else
98
0
    {
99
0
        OSL_FAIL( "Content::Content - unsupported content type string" );
100
0
        return STREAM;
101
0
    }
102
0
}
103
104
105
// Content Implementation.
106
107
108
// static ( "virtual" ctor )
109
rtl::Reference<Content> Content::create(
110
            const uno::Reference< uno::XComponentContext >& rxContext,
111
            ContentProvider* pProvider,
112
            const uno::Reference< ucb::XContentIdentifier >& Identifier )
113
4.00k
{
114
    // Fail, if resource does not exist.
115
4.00k
    ContentProperties aProps;
116
4.00k
    if ( !Content::loadData( pProvider,
117
4.00k
                             Uri( Identifier->getContentIdentifier() ),
118
4.00k
                             aProps ) )
119
4.00k
        return nullptr;
120
121
0
    return new Content( rxContext, pProvider, Identifier, std::move(aProps) );
122
4.00k
}
123
124
125
// static ( "virtual" ctor )
126
rtl::Reference<Content> Content::create(
127
            const uno::Reference< uno::XComponentContext >& rxContext,
128
            ContentProvider* pProvider,
129
            const uno::Reference< ucb::XContentIdentifier >& Identifier,
130
            const ucb::ContentInfo& Info )
131
0
{
132
0
    if ( Info.Type.isEmpty() )
133
0
        return nullptr;
134
135
0
    if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
136
0
    {
137
0
        OSL_FAIL( "Content::create - unsupported content type!" );
138
0
        return nullptr;
139
0
    }
140
141
0
    return new Content( rxContext, pProvider, Identifier, Info );
142
0
}
143
144
145
Content::Content(
146
            const uno::Reference< uno::XComponentContext > & rxContext,
147
            ContentProvider * pProvider,
148
            const uno::Reference< ucb::XContentIdentifier > & Identifier,
149
            ContentProperties aProps )
150
0
: ContentImplHelper( rxContext, pProvider, Identifier ),
151
0
  m_aProps(std::move( aProps )),
152
0
  m_eState( PERSISTENT ),
153
0
  m_pProvider( pProvider )
154
0
{
155
0
}
156
157
158
// ctor for a content just created via XContentCreator::createNewContent()
159
Content::Content(
160
            const uno::Reference< uno::XComponentContext >& rxContext,
161
            ContentProvider* pProvider,
162
            const uno::Reference< ucb::XContentIdentifier >& Identifier,
163
            const ucb::ContentInfo& Info )
164
0
  : ContentImplHelper( rxContext, pProvider, Identifier ),
165
0
  m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
166
0
  m_eState( TRANSIENT ),
167
0
  m_pProvider( pProvider )
168
0
{
169
0
}
170
171
172
// virtual
173
Content::~Content()
174
0
{
175
0
}
176
177
178
// XInterface methods.
179
180
181
// virtual
182
void SAL_CALL Content::acquire()
183
    noexcept
184
0
{
185
0
    ContentImplHelper::acquire();
186
0
}
187
188
189
// virtual
190
void SAL_CALL Content::release()
191
    noexcept
192
0
{
193
0
    ContentImplHelper::release();
194
0
}
195
196
197
// virtual
198
uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
199
0
{
200
0
    uno::Any aRet = ContentImplHelper::queryInterface( rType );
201
202
0
    if ( !aRet.hasValue() )
203
0
    {
204
0
        aRet = cppu::queryInterface(
205
0
                rType, static_cast< ucb::XContentCreator * >( this ) );
206
0
        if ( aRet.hasValue() )
207
0
        {
208
0
            if ( !m_aProps.isContentCreator() )
209
0
                return uno::Any();
210
0
        }
211
0
    }
212
213
0
    return aRet;
214
0
}
215
216
217
// XTypeProvider methods.
218
219
220
XTYPEPROVIDER_COMMON_IMPL( Content );
221
222
223
// virtual
224
uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
225
0
{
226
0
    if ( m_aProps.isContentCreator() )
227
0
    {
228
0
        static cppu::OTypeCollection s_aFolderTypes(
229
0
                    CPPU_TYPE_REF( lang::XTypeProvider ),
230
0
                    CPPU_TYPE_REF( lang::XServiceInfo ),
231
0
                    CPPU_TYPE_REF( lang::XComponent ),
232
0
                    CPPU_TYPE_REF( ucb::XContent ),
233
0
                    CPPU_TYPE_REF( ucb::XCommandProcessor ),
234
0
                    CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
235
0
                    CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
236
0
                    CPPU_TYPE_REF( beans::XPropertyContainer ),
237
0
                    CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
238
0
                    CPPU_TYPE_REF( container::XChild ),
239
0
                    CPPU_TYPE_REF( ucb::XContentCreator ) );
240
241
0
        return s_aFolderTypes.getTypes();
242
0
    }
243
0
    else
244
0
    {
245
0
        static cppu::OTypeCollection s_aDocumentTypes(
246
0
                    CPPU_TYPE_REF( lang::XTypeProvider ),
247
0
                    CPPU_TYPE_REF( lang::XServiceInfo ),
248
0
                    CPPU_TYPE_REF( lang::XComponent ),
249
0
                    CPPU_TYPE_REF( ucb::XContent ),
250
0
                    CPPU_TYPE_REF( ucb::XCommandProcessor ),
251
0
                    CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
252
0
                    CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
253
0
                    CPPU_TYPE_REF( beans::XPropertyContainer ),
254
0
                    CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
255
0
                    CPPU_TYPE_REF( container::XChild ) );
256
257
0
        return s_aDocumentTypes.getTypes();
258
0
    }
259
0
}
260
261
262
// XServiceInfo methods.
263
264
265
// virtual
266
OUString SAL_CALL Content::getImplementationName()
267
0
{
268
0
    return u"com.sun.star.comp.ucb.TransientDocumentsContent"_ustr;
269
0
}
270
271
272
// virtual
273
uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
274
0
{
275
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
276
277
0
    uno::Sequence< OUString > aSNS( 1 );
278
279
0
    if ( m_aProps.getType() == STREAM )
280
0
        aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsStreamContent";
281
0
    else if ( m_aProps.getType() == FOLDER )
282
0
        aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsFolderContent";
283
0
    else if ( m_aProps.getType() == DOCUMENT )
284
0
        aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsDocumentContent";
285
0
    else
286
0
        aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsRootContent";
287
288
0
    return aSNS;
289
0
}
290
291
292
// XContent methods.
293
294
295
// virtual
296
OUString SAL_CALL Content::getContentType()
297
0
{
298
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
299
0
    return m_aProps.getContentType();
300
0
}
301
302
303
// virtual
304
uno::Reference< ucb::XContentIdentifier > SAL_CALL
305
Content::getIdentifier()
306
0
{
307
0
    {
308
0
        osl::Guard< osl::Mutex > aGuard( m_aMutex );
309
310
        // Transient?
311
0
        if ( m_eState == TRANSIENT )
312
0
        {
313
            // Transient contents have no identifier.
314
0
            return uno::Reference< ucb::XContentIdentifier >();
315
0
        }
316
0
    }
317
0
    return ContentImplHelper::getIdentifier();
318
0
}
319
320
321
// XCommandProcessor methods.
322
323
324
// virtual
325
uno::Any SAL_CALL Content::execute(
326
        const ucb::Command& aCommand,
327
        sal_Int32 /*CommandId*/,
328
        const uno::Reference< ucb::XCommandEnvironment >& Environment )
329
0
{
330
0
    uno::Any aRet;
331
332
0
    if ( aCommand.Name == "getPropertyValues" )
333
0
    {
334
335
        // getPropertyValues
336
337
338
0
        uno::Sequence< beans::Property > Properties;
339
0
        if ( !( aCommand.Argument >>= Properties ) )
340
0
        {
341
0
            ucbhelper::cancelCommandExecution(
342
0
                uno::Any( lang::IllegalArgumentException(
343
0
                                    u"Wrong argument type!"_ustr,
344
0
                                    getXWeak(),
345
0
                                    -1 ) ),
346
0
                Environment );
347
            // Unreachable
348
0
        }
349
350
0
        aRet <<= getPropertyValues( Properties );
351
0
    }
352
0
    else if ( aCommand.Name == "setPropertyValues" )
353
0
    {
354
355
        // setPropertyValues
356
357
358
0
        uno::Sequence< beans::PropertyValue > aProperties;
359
0
        if ( !( aCommand.Argument >>= aProperties ) )
360
0
        {
361
0
            ucbhelper::cancelCommandExecution(
362
0
                uno::Any( lang::IllegalArgumentException(
363
0
                                    u"Wrong argument type!"_ustr,
364
0
                                    getXWeak(),
365
0
                                    -1 ) ),
366
0
                Environment );
367
            // Unreachable
368
0
        }
369
370
0
        if ( !aProperties.hasElements() )
371
0
        {
372
0
            ucbhelper::cancelCommandExecution(
373
0
                uno::Any( lang::IllegalArgumentException(
374
0
                                    u"No properties!"_ustr,
375
0
                                    getXWeak(),
376
0
                                    -1 ) ),
377
0
                Environment );
378
            // Unreachable
379
0
        }
380
381
0
        aRet <<= setPropertyValues( aProperties, Environment );
382
0
    }
383
0
    else if ( aCommand.Name == "getPropertySetInfo" )
384
0
    {
385
386
        // getPropertySetInfo
387
388
389
0
        aRet <<= getPropertySetInfo( Environment );
390
0
    }
391
0
    else if ( aCommand.Name == "getCommandInfo" )
392
0
    {
393
394
        // getCommandInfo
395
396
397
0
        aRet <<= getCommandInfo( Environment );
398
0
    }
399
0
    else if ( aCommand.Name == "open" )
400
0
    {
401
402
        // open
403
404
405
0
        ucb::OpenCommandArgument2 aOpenCommand;
406
0
        if ( !( aCommand.Argument >>= aOpenCommand ) )
407
0
        {
408
0
            ucbhelper::cancelCommandExecution(
409
0
                uno::Any( lang::IllegalArgumentException(
410
0
                                    u"Wrong argument type!"_ustr,
411
0
                                    getXWeak(),
412
0
                                    -1 ) ),
413
0
                Environment );
414
            // Unreachable
415
0
        }
416
417
0
        aRet = open( aOpenCommand, Environment );
418
0
    }
419
0
    else if ( aCommand.Name == "insert" )
420
0
    {
421
422
        // insert ( Supported by folders and streams only )
423
424
425
0
        ContentType eType = m_aProps.getType();
426
0
        if ( ( eType != FOLDER ) && ( eType != STREAM ) )
427
0
        {
428
0
            ucbhelper::cancelCommandExecution(
429
0
                uno::Any( ucb::UnsupportedCommandException(
430
0
                                u"insert command only supported by "
431
0
                                "folders and streams!"_ustr,
432
0
                                getXWeak() ) ),
433
0
                Environment );
434
            // Unreachable
435
0
        }
436
437
0
        if ( eType == STREAM )
438
0
        {
439
0
            Uri aUri( m_xIdentifier->getContentIdentifier() );
440
0
            Uri aParentUri( aUri.getParentUri() );
441
0
            if ( aParentUri.isDocument() )
442
0
            {
443
0
                ucbhelper::cancelCommandExecution(
444
0
                    uno::Any( ucb::UnsupportedCommandException(
445
0
                                    u"insert command not supported by "
446
0
                                    "streams that are direct children "
447
0
                                    "of document root!"_ustr,
448
0
                                    getXWeak() ) ),
449
0
                    Environment );
450
                // Unreachable
451
0
            }
452
0
        }
453
454
0
        ucb::InsertCommandArgument aArg;
455
0
        if ( !( aCommand.Argument >>= aArg ) )
456
0
        {
457
0
            ucbhelper::cancelCommandExecution(
458
0
                uno::Any( lang::IllegalArgumentException(
459
0
                                    u"Wrong argument type!"_ustr,
460
0
                                    getXWeak(),
461
0
                                    -1 ) ),
462
0
                Environment );
463
            // Unreachable
464
0
        }
465
466
0
        sal_Int32 nNameClash = aArg.ReplaceExisting
467
0
                             ? ucb::NameClash::OVERWRITE
468
0
                             : ucb::NameClash::ERROR;
469
0
        insert( aArg.Data, nNameClash, Environment );
470
0
    }
471
0
    else if ( aCommand.Name == "delete" )
472
0
    {
473
474
        // delete ( Supported by folders and streams only )
475
476
477
0
        {
478
0
            osl::MutexGuard aGuard( m_aMutex );
479
480
0
            ContentType eType = m_aProps.getType();
481
0
            if ( ( eType != FOLDER ) && ( eType != STREAM ) )
482
0
            {
483
0
                ucbhelper::cancelCommandExecution(
484
0
                    uno::Any( ucb::UnsupportedCommandException(
485
0
                                    u"delete command only supported by "
486
0
                                    "folders and streams!"_ustr,
487
0
                                    getXWeak() ) ),
488
0
                    Environment );
489
                // Unreachable
490
0
            }
491
0
        }
492
493
0
        bool bDeletePhysical = false;
494
0
        aCommand.Argument >>= bDeletePhysical;
495
0
        destroy( bDeletePhysical, Environment );
496
497
        // Remove own and all children's persistent data.
498
0
        if ( !removeData() )
499
0
        {
500
0
            uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
501
0
            {
502
0
                 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
503
0
            }));
504
0
            ucbhelper::cancelCommandExecution(
505
0
                ucb::IOErrorCode_CANT_WRITE,
506
0
                aArgs,
507
0
                Environment,
508
0
                u"Cannot remove persistent data!"_ustr,
509
0
                this );
510
            // Unreachable
511
0
        }
512
513
        // Remove own and all children's Additional Core Properties.
514
0
        removeAdditionalPropertySet();
515
0
    }
516
0
    else if ( aCommand.Name == "transfer" )
517
0
    {
518
519
        // transfer ( Supported by document and folders only )
520
521
522
0
        {
523
0
            osl::MutexGuard aGuard( m_aMutex );
524
525
0
            ContentType eType = m_aProps.getType();
526
0
            if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
527
0
            {
528
0
                ucbhelper::cancelCommandExecution(
529
0
                    uno::Any( ucb::UnsupportedCommandException(
530
0
                                    u"transfer command only supported "
531
0
                                    "by folders and documents!"_ustr,
532
0
                                    getXWeak() ) ),
533
0
                    Environment );
534
                // Unreachable
535
0
            }
536
0
        }
537
538
0
        ucb::TransferInfo aInfo;
539
0
        if ( !( aCommand.Argument >>= aInfo ) )
540
0
        {
541
0
            OSL_FAIL( "Wrong argument type!" );
542
0
            ucbhelper::cancelCommandExecution(
543
0
                uno::Any( lang::IllegalArgumentException(
544
0
                                    u"Wrong argument type!"_ustr,
545
0
                                    getXWeak(),
546
0
                                    -1 ) ),
547
0
                Environment );
548
            // Unreachable
549
0
        }
550
551
0
        transfer( aInfo, Environment );
552
0
    }
553
0
    else if ( aCommand.Name == "createNewContent" )
554
0
    {
555
556
        // createNewContent ( Supported by document and folders only )
557
558
559
0
        {
560
0
            osl::MutexGuard aGuard( m_aMutex );
561
562
0
            ContentType eType = m_aProps.getType();
563
0
            if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
564
0
            {
565
0
                ucbhelper::cancelCommandExecution(
566
0
                    uno::Any( ucb::UnsupportedCommandException(
567
0
                                    u"createNewContent command only "
568
0
                                    "supported by folders and "
569
0
                                    "documents!"_ustr,
570
0
                                    getXWeak() ) ),
571
0
                    Environment );
572
                // Unreachable
573
0
            }
574
0
        }
575
576
0
        ucb::ContentInfo aInfo;
577
0
        if ( !( aCommand.Argument >>= aInfo ) )
578
0
        {
579
0
            OSL_FAIL( "Wrong argument type!" );
580
0
            ucbhelper::cancelCommandExecution(
581
0
                uno::Any( lang::IllegalArgumentException(
582
0
                                    u"Wrong argument type!"_ustr,
583
0
                                    getXWeak(),
584
0
                                    -1 ) ),
585
0
                Environment );
586
            // Unreachable
587
0
        }
588
589
0
        aRet <<= createNewContent( aInfo );
590
0
    }
591
0
    else
592
0
    {
593
594
        // Unsupported command
595
596
597
0
        ucbhelper::cancelCommandExecution(
598
0
            uno::Any( ucb::UnsupportedCommandException(
599
0
                                OUString(),
600
0
                                getXWeak() ) ),
601
0
            Environment );
602
        // Unreachable
603
0
    }
604
605
0
    return aRet;
606
0
}
607
608
609
// virtual
610
void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
611
0
{
612
0
}
613
614
615
// XContentCreator methods.
616
617
618
// virtual
619
uno::Sequence< ucb::ContentInfo > SAL_CALL
620
Content::queryCreatableContentsInfo()
621
0
{
622
0
    return m_aProps.getCreatableContentsInfo();
623
0
}
624
625
626
// virtual
627
uno::Reference< ucb::XContent > SAL_CALL
628
Content::createNewContent( const ucb::ContentInfo& Info )
629
0
{
630
0
    if ( m_aProps.isContentCreator() )
631
0
    {
632
0
        osl::Guard< osl::Mutex > aGuard( m_aMutex );
633
634
0
        if ( Info.Type.isEmpty() )
635
0
            return uno::Reference< ucb::XContent >();
636
637
0
        bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
638
639
        // streams cannot be created as direct children of document root
640
0
        if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
641
0
        {
642
0
            OSL_FAIL( "Content::createNewContent - streams cannot be "
643
0
                        "created as direct children of document root!" );
644
0
            return uno::Reference< ucb::XContent >();
645
0
        }
646
0
        if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
647
0
        {
648
0
            OSL_FAIL( "Content::createNewContent - unsupported type!" );
649
0
            return uno::Reference< ucb::XContent >();
650
0
        }
651
652
0
        OUString aURL = m_xIdentifier->getContentIdentifier();
653
654
0
        OSL_ENSURE( !aURL.isEmpty(),
655
0
                    "Content::createNewContent - empty identifier!" );
656
657
0
        if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
658
0
            aURL += "/";
659
660
0
        if ( bCreateFolder )
661
0
            aURL += "New_Folder";
662
0
        else
663
0
            aURL += "New_Stream";
664
665
0
        uno::Reference< ucb::XContentIdentifier > xId
666
0
            = new ::ucbhelper::ContentIdentifier( aURL );
667
668
0
        return create( m_xContext, m_pProvider, xId, Info );
669
0
    }
670
0
    else
671
0
    {
672
0
        OSL_FAIL( "createNewContent called on non-contentcreator object!" );
673
0
        return uno::Reference< ucb::XContent >();
674
0
    }
675
0
}
676
677
678
// virtual
679
OUString Content::getParentURL()
680
0
{
681
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
682
0
    Uri aUri( m_xIdentifier->getContentIdentifier() );
683
0
    return aUri.getParentUri();
684
0
}
685
686
687
uno::Reference< ucb::XContentIdentifier >
688
Content::makeNewIdentifier( const OUString& rTitle )
689
0
{
690
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
691
692
    // Assemble new content identifier...
693
0
    Uri aUri( m_xIdentifier->getContentIdentifier() );
694
0
    OUString aNewURL = aUri.getParentUri() + ::ucb_impl::urihelper::encodeSegment( rTitle );
695
696
0
    return
697
0
        uno::Reference< ucb::XContentIdentifier >(
698
0
            new ::ucbhelper::ContentIdentifier( aNewURL ) );
699
0
}
700
701
702
void Content::queryChildren( ContentRefList& rChildren )
703
0
{
704
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
705
706
    // Only folders (root, documents, folders) have children.
707
0
    if ( !m_aProps.getIsFolder() )
708
0
        return;
709
710
    // Obtain a list with a snapshot of all currently instantiated contents
711
    // from provider and extract the contents which are direct children
712
    // of this content.
713
714
0
    ::ucbhelper::ContentRefList aAllContents;
715
0
    m_xProvider->queryExistingContents( aAllContents );
716
717
0
    OUString aURL = m_xIdentifier->getContentIdentifier();
718
0
    sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
719
720
0
    if ( nURLPos != ( aURL.getLength() - 1 ) )
721
0
    {
722
        // No trailing slash found. Append.
723
0
        aURL += "/";
724
0
    }
725
726
0
    sal_Int32 nLen = aURL.getLength();
727
728
0
    for ( const auto& rContent : aAllContents )
729
0
    {
730
0
        ::ucbhelper::ContentImplHelperRef xChild = rContent;
731
0
        OUString aChildURL
732
0
            = xChild->getIdentifier()->getContentIdentifier();
733
734
        // Is aURL a prefix of aChildURL?
735
0
        if ( ( aChildURL.getLength() > nLen ) &&
736
0
             ( aChildURL.startsWith( aURL ) ) )
737
0
        {
738
0
            sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
739
740
0
            if ( ( nPos == -1 ) ||
741
0
                 ( nPos == ( aChildURL.getLength() - 1 ) ) )
742
0
            {
743
                // No further slashes / only a final slash. It's a child!
744
0
                rChildren.emplace_back(
745
0
                        static_cast< Content * >( xChild.get() ) );
746
0
            }
747
0
        }
748
0
    }
749
0
}
750
751
752
bool Content::exchangeIdentity(
753
            const uno::Reference< ucb::XContentIdentifier >& xNewId )
754
0
{
755
0
    if ( !xNewId.is() )
756
0
        return false;
757
758
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
759
760
0
    uno::Reference< ucb::XContent > xThis = this;
761
762
    // Already persistent?
763
0
    if ( m_eState != PERSISTENT )
764
0
    {
765
0
        OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
766
0
        return false;
767
0
    }
768
769
    // Only folders and streams can be renamed -> exchange identity.
770
0
    ContentType eType = m_aProps.getType();
771
0
    if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
772
0
    {
773
0
        OSL_FAIL( "Content::exchangeIdentity - "
774
0
                               "Not supported by root or document!" );
775
0
        return false;
776
0
    }
777
778
    // Exchange own identity.
779
780
    // Fail, if a content with given id already exists.
781
0
    if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
782
0
    {
783
0
        OUString aOldURL = m_xIdentifier->getContentIdentifier();
784
785
0
        aGuard.clear();
786
0
        if ( exchange( xNewId ) )
787
0
        {
788
0
            if ( eType == FOLDER )
789
0
            {
790
                // Process instantiated children...
791
792
0
                ContentRefList aChildren;
793
0
                queryChildren( aChildren );
794
795
0
                for ( const auto& rChild : aChildren )
796
0
                {
797
0
                    ContentRef xChild = rChild;
798
799
                    // Create new content identifier for the child...
800
0
                    uno::Reference< ucb::XContentIdentifier > xOldChildId
801
0
                                                    = xChild->getIdentifier();
802
0
                    OUString aOldChildURL
803
0
                        = xOldChildId->getContentIdentifier();
804
0
                    OUString aNewChildURL
805
0
                        = aOldChildURL.replaceAt(
806
0
                                        0,
807
0
                                        aOldURL.getLength(),
808
0
                                        xNewId->getContentIdentifier() );
809
0
                    uno::Reference< ucb::XContentIdentifier > xNewChildId
810
0
                        = new ::ucbhelper::ContentIdentifier( aNewChildURL );
811
812
0
                    if ( !xChild->exchangeIdentity( xNewChildId ) )
813
0
                        return false;
814
0
                }
815
0
            }
816
0
            return true;
817
0
        }
818
0
    }
819
820
0
    OSL_FAIL( "Content::exchangeIdentity - "
821
0
                "Panic! Cannot exchange identity!" );
822
0
    return false;
823
0
}
824
825
826
// static
827
uno::Reference< sdbc::XRow > Content::getPropertyValues(
828
                const uno::Reference< uno::XComponentContext >& rxContext,
829
                const uno::Sequence< beans::Property >& rProperties,
830
                ContentProvider* pProvider,
831
                const OUString& rContentId )
832
0
{
833
0
    ContentProperties aData;
834
0
    if ( loadData( pProvider, Uri(rContentId), aData ) )
835
0
    {
836
0
        return getPropertyValues(
837
0
            rxContext, rProperties, aData, pProvider, rContentId );
838
0
    }
839
0
    else
840
0
    {
841
0
        rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
842
0
            = new ::ucbhelper::PropertyValueSet( rxContext );
843
844
0
        for ( const beans::Property& rProp : rProperties )
845
0
            xRow->appendVoid( rProp );
846
847
0
        return xRow;
848
0
    }
849
0
}
850
851
852
// static
853
uno::Reference< sdbc::XRow > Content::getPropertyValues(
854
                const uno::Reference< uno::XComponentContext >& rxContext,
855
                const uno::Sequence< beans::Property >& rProperties,
856
                const ContentProperties& rData,
857
                ContentProvider* pProvider,
858
                const OUString& rContentId )
859
0
{
860
    // Note: Empty sequence means "get values of all supported properties".
861
862
0
    rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
863
0
        = new ::ucbhelper::PropertyValueSet( rxContext );
864
865
0
    if ( rProperties.hasElements() )
866
0
    {
867
0
        uno::Reference< beans::XPropertySet > xAdditionalPropSet;
868
0
        bool bTriedToGetAdditionalPropSet = false;
869
870
0
        for ( const beans::Property& rProp : rProperties )
871
0
        {
872
            // Process Core properties.
873
874
0
            if ( rProp.Name == "ContentType" )
875
0
            {
876
0
                xRow->appendString ( rProp, rData.getContentType() );
877
0
            }
878
0
            else if ( rProp.Name == "Title" )
879
0
            {
880
0
                xRow->appendString ( rProp, rData.getTitle() );
881
0
            }
882
0
            else if ( rProp.Name == "IsDocument" )
883
0
            {
884
0
                xRow->appendBoolean( rProp, rData.getIsDocument() );
885
0
            }
886
0
            else if ( rProp.Name == "IsFolder" )
887
0
            {
888
0
                xRow->appendBoolean( rProp, rData.getIsFolder() );
889
0
            }
890
0
            else if ( rProp.Name == "CreatableContentsInfo" )
891
0
            {
892
0
                xRow->appendObject(
893
0
                    rProp, uno::Any( rData.getCreatableContentsInfo() ) );
894
0
            }
895
0
            else if ( rProp.Name == "DateModified" )
896
0
            {
897
                // DateModified is only supported by streams.
898
0
                ContentType eType = rData.getType();
899
0
                if ( eType == STREAM )
900
0
                {
901
0
                    xRow->appendObject(
902
0
                        rProp,
903
0
                        uno::Any(
904
0
                            pProvider->queryStreamDateModified( rContentId ) ) );
905
0
                }
906
0
                else
907
0
                    xRow->appendVoid( rProp );
908
0
            }
909
0
            else if ( rProp.Name == "Storage" )
910
0
            {
911
                // Storage is only supported by folders.
912
0
                ContentType eType = rData.getType();
913
0
                if ( eType == FOLDER )
914
0
                    xRow->appendObject(
915
0
                        rProp,
916
0
                        uno::Any(
917
0
                            pProvider->queryStorageClone( rContentId ) ) );
918
0
                else
919
0
                    xRow->appendVoid( rProp );
920
0
            }
921
0
            else if ( rProp.Name == "DocumentModel" )
922
0
            {
923
                // DocumentModel is only supported by documents.
924
0
                ContentType eType = rData.getType();
925
0
                if ( eType == DOCUMENT )
926
0
                    xRow->appendObject(
927
0
                        rProp,
928
0
                        uno::Any(
929
0
                            pProvider->queryDocumentModel( rContentId ) ) );
930
0
                else
931
0
                    xRow->appendVoid( rProp );
932
0
            }
933
0
            else
934
0
            {
935
                // Not a Core Property! Maybe it's an Additional Core Property?!
936
937
0
                if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
938
0
                {
939
0
                    xAdditionalPropSet =
940
0
                            pProvider->getAdditionalPropertySet( rContentId,
941
0
                                                                 false );
942
0
                    bTriedToGetAdditionalPropSet = true;
943
0
                }
944
945
0
                if ( xAdditionalPropSet.is() )
946
0
                {
947
0
                    if ( !xRow->appendPropertySetValue(
948
0
                                                xAdditionalPropSet,
949
0
                                                rProp ) )
950
0
                    {
951
                        // Append empty entry.
952
0
                        xRow->appendVoid( rProp );
953
0
                    }
954
0
                }
955
0
                else
956
0
                {
957
                    // Append empty entry.
958
0
                    xRow->appendVoid( rProp );
959
0
                }
960
0
            }
961
0
        }
962
0
    }
963
0
    else
964
0
    {
965
        // Append all Core Properties.
966
0
        xRow->appendString (
967
0
            beans::Property( u"ContentType"_ustr,
968
0
                      -1,
969
0
                      cppu::UnoType<OUString>::get(),
970
0
                      beans::PropertyAttribute::BOUND
971
0
                        | beans::PropertyAttribute::READONLY ),
972
0
            rData.getContentType() );
973
974
0
        ContentType eType = rData.getType();
975
976
0
        xRow->appendString (
977
0
            beans::Property( u"Title"_ustr,
978
0
                      -1,
979
0
                      cppu::UnoType<OUString>::get(),
980
                      // Title is read-only for root and documents.
981
0
                      beans::PropertyAttribute::BOUND |
982
0
                      ( ( eType == ROOT ) || ( eType == DOCUMENT )
983
0
                        ? beans::PropertyAttribute::READONLY
984
0
                        : 0 ) ),
985
0
            rData.getTitle() );
986
0
        xRow->appendBoolean(
987
0
            beans::Property( u"IsDocument"_ustr,
988
0
                      -1,
989
0
                      cppu::UnoType<bool>::get(),
990
0
                      beans::PropertyAttribute::BOUND
991
0
                        | beans::PropertyAttribute::READONLY ),
992
0
            rData.getIsDocument() );
993
0
        xRow->appendBoolean(
994
0
            beans::Property( u"IsFolder"_ustr,
995
0
                      -1,
996
0
                      cppu::UnoType<bool>::get(),
997
0
                      beans::PropertyAttribute::BOUND
998
0
                        | beans::PropertyAttribute::READONLY ),
999
0
            rData.getIsFolder() );
1000
0
        xRow->appendObject(
1001
0
            beans::Property(
1002
0
                u"CreatableContentsInfo"_ustr,
1003
0
                -1,
1004
0
                cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
1005
0
                beans::PropertyAttribute::BOUND
1006
0
                | beans::PropertyAttribute::READONLY ),
1007
0
            uno::Any( rData.getCreatableContentsInfo() ) );
1008
1009
        // DateModified is only supported by streams.
1010
0
        if ( eType == STREAM )
1011
0
        {
1012
0
            xRow->appendObject(
1013
0
                beans::Property( u"DateModified"_ustr,
1014
0
                          -1,
1015
0
                          cppu::UnoType<css::util::DateTime>::get(),
1016
0
                          beans::PropertyAttribute::BOUND
1017
0
                            | beans::PropertyAttribute::READONLY ),
1018
0
                uno::Any( pProvider->queryStreamDateModified( rContentId ) ) );
1019
0
        }
1020
1021
        // Storage is only supported by folders.
1022
0
        if ( eType == FOLDER )
1023
0
            xRow->appendObject(
1024
0
                beans::Property( u"Storage"_ustr,
1025
0
                          -1,
1026
0
                          cppu::UnoType<embed::XStorage>::get(),
1027
0
                          beans::PropertyAttribute::BOUND
1028
0
                            | beans::PropertyAttribute::READONLY ),
1029
0
                uno::Any( pProvider->queryStorageClone( rContentId ) ) );
1030
1031
        // DocumentModel is only supported by documents.
1032
0
        if ( eType == DOCUMENT )
1033
0
            xRow->appendObject(
1034
0
                beans::Property( u"DocumentModel"_ustr,
1035
0
                          -1,
1036
0
                          cppu::UnoType<frame::XModel>::get(),
1037
0
                          beans::PropertyAttribute::BOUND
1038
0
                            | beans::PropertyAttribute::READONLY ),
1039
0
                uno::Any(
1040
0
                    pProvider->queryDocumentModel( rContentId ) ) );
1041
1042
        // Append all Additional Core Properties.
1043
1044
0
        uno::Reference< beans::XPropertySet > xSet =
1045
0
            pProvider->getAdditionalPropertySet( rContentId, false );
1046
0
        xRow->appendPropertySet( xSet );
1047
0
    }
1048
1049
0
    return xRow;
1050
0
}
1051
1052
1053
uno::Reference< sdbc::XRow > Content::getPropertyValues(
1054
                        const uno::Sequence< beans::Property >& rProperties )
1055
0
{
1056
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
1057
0
    return getPropertyValues( m_xContext,
1058
0
                              rProperties,
1059
0
                              m_aProps,
1060
0
                              m_pProvider,
1061
0
                              m_xIdentifier->getContentIdentifier() );
1062
0
}
1063
1064
1065
uno::Sequence< uno::Any > Content::setPropertyValues(
1066
        const uno::Sequence< beans::PropertyValue >& rValues,
1067
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1068
0
{
1069
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1070
1071
0
    uno::Sequence< uno::Any > aRet( rValues.getLength() );
1072
0
    auto aRetRange = asNonConstRange(aRet);
1073
0
    uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1074
0
    sal_Int32 nChanged = 0;
1075
1076
0
    beans::PropertyChangeEvent aEvent;
1077
0
    aEvent.Source         = getXWeak();
1078
0
    aEvent.Further        = false;
1079
0
    aEvent.PropertyHandle = -1;
1080
1081
0
    const beans::PropertyValue* pValues = rValues.getConstArray();
1082
0
    sal_Int32 nCount = rValues.getLength();
1083
1084
0
    uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1085
0
    bool bTriedToGetAdditionalPropSet = false;
1086
1087
0
    bool bExchange = false;
1088
0
    OUString aOldTitle;
1089
0
    sal_Int32 nTitlePos = -1;
1090
1091
0
    for ( sal_Int32 n = 0; n < nCount; ++n )
1092
0
    {
1093
0
        const beans::PropertyValue& rValue = pValues[ n ];
1094
1095
0
        if ( rValue.Name == "ContentType" )
1096
0
        {
1097
            // Read-only property!
1098
0
            aRetRange[ n ] <<= lang::IllegalAccessException(
1099
0
                            u"Property is read-only!"_ustr,
1100
0
                            getXWeak() );
1101
0
        }
1102
0
        else if ( rValue.Name == "IsDocument" )
1103
0
        {
1104
            // Read-only property!
1105
0
            aRetRange[ n ] <<= lang::IllegalAccessException(
1106
0
                            u"Property is read-only!"_ustr,
1107
0
                            getXWeak() );
1108
0
        }
1109
0
        else if ( rValue.Name == "IsFolder" )
1110
0
        {
1111
            // Read-only property!
1112
0
            aRetRange[ n ] <<= lang::IllegalAccessException(
1113
0
                            u"Property is read-only!"_ustr,
1114
0
                            getXWeak() );
1115
0
        }
1116
0
        else if ( rValue.Name == "CreatableContentsInfo" )
1117
0
        {
1118
            // Read-only property!
1119
0
            aRetRange[ n ] <<= lang::IllegalAccessException(
1120
0
                            u"Property is read-only!"_ustr,
1121
0
                            getXWeak() );
1122
0
        }
1123
0
        else if ( rValue.Name == "Title" )
1124
0
        {
1125
            // Title is read-only for root and documents.
1126
0
            ContentType eType = m_aProps.getType();
1127
0
            if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1128
0
            {
1129
0
                aRetRange[ n ] <<= lang::IllegalAccessException(
1130
0
                                u"Property is read-only!"_ustr,
1131
0
                                getXWeak() );
1132
0
            }
1133
0
            else
1134
0
            {
1135
0
                OUString aNewValue;
1136
0
                if ( rValue.Value >>= aNewValue )
1137
0
                {
1138
                    // No empty titles!
1139
0
                    if ( !aNewValue.isEmpty() )
1140
0
                    {
1141
0
                        if ( aNewValue != m_aProps.getTitle() )
1142
0
                        {
1143
                            // modified title -> modified URL -> exchange !
1144
0
                            if ( m_eState == PERSISTENT )
1145
0
                                bExchange = true;
1146
1147
0
                            aOldTitle = m_aProps.getTitle();
1148
0
                            m_aProps.setTitle( aNewValue );
1149
1150
                            // property change event will be sent later...
1151
1152
                            // remember position within sequence of values
1153
                            // (for error handling).
1154
0
                            nTitlePos = n;
1155
0
                        }
1156
0
                    }
1157
0
                    else
1158
0
                    {
1159
0
                        aRetRange[ n ] <<= lang::IllegalArgumentException(
1160
0
                                    u"Empty Title not allowed!"_ustr,
1161
0
                                    getXWeak(),
1162
0
                                    -1 );
1163
0
                    }
1164
0
                }
1165
0
                else
1166
0
                {
1167
0
                    aRetRange[ n ] <<= beans::IllegalTypeException(
1168
0
                                u"Title Property value has wrong type!"_ustr,
1169
0
                                getXWeak() );
1170
0
                }
1171
0
            }
1172
0
        }
1173
0
        else if ( rValue.Name == "Storage" )
1174
0
        {
1175
0
            ContentType eType = m_aProps.getType();
1176
0
            if ( eType == FOLDER )
1177
0
            {
1178
0
                aRetRange[ n ] <<= lang::IllegalAccessException(
1179
0
                                u"Property is read-only!"_ustr,
1180
0
                                getXWeak() );
1181
0
            }
1182
0
            else
1183
0
            {
1184
                // Storage is only supported by folders.
1185
0
                aRetRange[ n ] <<= beans::UnknownPropertyException(
1186
0
                            u"Storage property only supported by folders"_ustr,
1187
0
                            getXWeak() );
1188
0
            }
1189
0
        }
1190
0
        else if ( rValue.Name == "DocumentModel" )
1191
0
        {
1192
0
            ContentType eType = m_aProps.getType();
1193
0
            if ( eType == DOCUMENT )
1194
0
            {
1195
0
                aRetRange[ n ] <<= lang::IllegalAccessException(
1196
0
                                u"Property is read-only!"_ustr,
1197
0
                                getXWeak() );
1198
0
            }
1199
0
            else
1200
0
            {
1201
                // Storage is only supported by folders.
1202
0
                aRetRange[ n ] <<= beans::UnknownPropertyException(
1203
0
                            u"DocumentModel property only supported by documents"_ustr,
1204
0
                            getXWeak() );
1205
0
            }
1206
0
        }
1207
0
        else
1208
0
        {
1209
            // Not a Core Property! Maybe it's an Additional Core Property?!
1210
1211
0
            if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1212
0
            {
1213
0
                xAdditionalPropSet = getAdditionalPropertySet( false );
1214
0
                bTriedToGetAdditionalPropSet = true;
1215
0
            }
1216
1217
0
            if ( xAdditionalPropSet.is() )
1218
0
            {
1219
0
                try
1220
0
                {
1221
0
                    uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1222
0
                                                                rValue.Name );
1223
0
                    if ( aOldValue != rValue.Value )
1224
0
                    {
1225
0
                        xAdditionalPropSet->setPropertyValue(
1226
0
                                                rValue.Name, rValue.Value );
1227
1228
0
                        aEvent.PropertyName = rValue.Name;
1229
0
                        aEvent.OldValue     = std::move(aOldValue);
1230
0
                        aEvent.NewValue     = rValue.Value;
1231
1232
0
                        aChanges.getArray()[ nChanged ] = aEvent;
1233
0
                        nChanged++;
1234
0
                    }
1235
0
                }
1236
0
                catch ( beans::UnknownPropertyException const & e )
1237
0
                {
1238
0
                    aRetRange[ n ] <<= e;
1239
0
                }
1240
0
                catch ( lang::WrappedTargetException const & e )
1241
0
                {
1242
0
                    aRetRange[ n ] <<= e;
1243
0
                }
1244
0
                catch ( beans::PropertyVetoException const & e )
1245
0
                {
1246
0
                    aRetRange[ n ] <<= e;
1247
0
                }
1248
0
                catch ( lang::IllegalArgumentException const & e )
1249
0
                {
1250
0
                    aRetRange[ n ] <<= e;
1251
0
                }
1252
0
            }
1253
0
            else
1254
0
            {
1255
0
                aRetRange[ n ] <<= uno::Exception(
1256
0
                                u"No property set for storing the value!"_ustr,
1257
0
                                getXWeak() );
1258
0
            }
1259
0
        }
1260
0
    }
1261
1262
0
    if ( bExchange )
1263
0
    {
1264
0
        uno::Reference< ucb::XContentIdentifier > xOldId
1265
0
            = m_xIdentifier;
1266
0
        uno::Reference< ucb::XContentIdentifier > xNewId
1267
0
            = makeNewIdentifier( m_aProps.getTitle() );
1268
1269
0
        aGuard.clear();
1270
0
        if ( exchangeIdentity( xNewId ) )
1271
0
        {
1272
            // Adapt persistent data.
1273
0
            renameData( xOldId, xNewId );
1274
1275
            // Adapt Additional Core Properties.
1276
0
            renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1277
0
                                         xNewId->getContentIdentifier() );
1278
0
        }
1279
0
        else
1280
0
        {
1281
            // Roll-back.
1282
0
            m_aProps.setTitle( aOldTitle );
1283
0
            aOldTitle.clear();
1284
1285
            // Set error .
1286
0
            aRetRange[ nTitlePos ] <<= uno::Exception(
1287
0
                    u"Exchange failed!"_ustr,
1288
0
                    getXWeak() );
1289
0
        }
1290
0
    }
1291
1292
0
    if ( !aOldTitle.isEmpty() )
1293
0
    {
1294
0
        aEvent.PropertyName = "Title";
1295
0
        aEvent.OldValue     <<= aOldTitle;
1296
0
        aEvent.NewValue     <<= m_aProps.getTitle();
1297
1298
0
        aChanges.getArray()[ nChanged ] = std::move(aEvent);
1299
0
        nChanged++;
1300
0
    }
1301
1302
0
    if ( nChanged > 0 )
1303
0
    {
1304
        // Save changes, if content was already made persistent.
1305
0
        if ( !bExchange && ( m_eState == PERSISTENT ) )
1306
0
        {
1307
0
            if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1308
0
            {
1309
0
                uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1310
0
                {
1311
0
                     {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1312
0
                }));
1313
0
                ucbhelper::cancelCommandExecution(
1314
0
                    ucb::IOErrorCode_CANT_WRITE,
1315
0
                    aArgs,
1316
0
                    xEnv,
1317
0
                    u"Cannot store persistent data!"_ustr,
1318
0
                    this );
1319
                // Unreachable
1320
0
            }
1321
0
        }
1322
1323
0
        aChanges.realloc( nChanged );
1324
1325
0
        aGuard.clear();
1326
0
        notifyPropertiesChange( aChanges );
1327
0
    }
1328
1329
0
    return aRet;
1330
0
}
1331
1332
1333
uno::Any Content::open(
1334
                const ucb::OpenCommandArgument2& rArg,
1335
                const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1336
0
{
1337
0
    if ( rArg.Mode == ucb::OpenMode::ALL ||
1338
0
         rArg.Mode == ucb::OpenMode::FOLDERS ||
1339
0
         rArg.Mode == ucb::OpenMode::DOCUMENTS )
1340
0
    {
1341
1342
        // open command for a folder content
1343
1344
1345
0
        uno::Reference< ucb::XDynamicResultSet > xSet
1346
0
            = new DynamicResultSet( m_xContext, this, rArg );
1347
0
        return uno::Any( xSet );
1348
0
    }
1349
0
    else
1350
0
    {
1351
1352
        // open command for a document content
1353
1354
1355
0
        if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1356
0
             ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1357
0
        {
1358
            // Currently(?) unsupported.
1359
0
            ucbhelper::cancelCommandExecution(
1360
0
                uno::Any( ucb::UnsupportedOpenModeException(
1361
0
                                    OUString(),
1362
0
                                    getXWeak(),
1363
0
                                    sal_Int16( rArg.Mode ) ) ),
1364
0
                xEnv );
1365
            // Unreachable
1366
0
        }
1367
1368
0
        osl::Guard< osl::Mutex > aGuard( m_aMutex );
1369
1370
0
        uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1371
0
                                        rArg.Sink, uno::UNO_QUERY );
1372
0
        if ( xDataStreamer.is() )
1373
0
        {
1374
            // May throw CommandFailedException, DocumentPasswordRequest!
1375
0
            uno::Reference< io::XStream > xStream = getStream( xEnv );
1376
0
            if ( !xStream.is() )
1377
0
            {
1378
                // No interaction if we are not persistent!
1379
0
                uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1380
0
                {
1381
0
                    {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1382
0
                }));
1383
0
                ucbhelper::cancelCommandExecution(
1384
0
                    ucb::IOErrorCode_CANT_READ,
1385
0
                    aArgs,
1386
0
                    m_eState == PERSISTENT
1387
0
                        ? xEnv
1388
0
                        : uno::Reference< ucb::XCommandEnvironment >(),
1389
0
                    u"Got no data stream!"_ustr,
1390
0
                    this );
1391
                // Unreachable
1392
0
            }
1393
1394
            // Done.
1395
0
            xDataStreamer->setStream( xStream );
1396
0
        }
1397
0
        else
1398
0
        {
1399
0
            uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1400
0
            if ( xOut.is() )
1401
0
            {
1402
                // PUSH: write data into xOut
1403
1404
                // May throw CommandFailedException, DocumentPasswordRequest!
1405
0
                uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1406
0
                if ( !xIn.is() )
1407
0
                {
1408
                    // No interaction if we are not persistent!
1409
0
                    uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1410
0
                    {
1411
0
                        {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1412
0
                    }));
1413
0
                    ucbhelper::cancelCommandExecution(
1414
0
                        ucb::IOErrorCode_CANT_READ,
1415
0
                        aArgs,
1416
0
                        m_eState == PERSISTENT
1417
0
                            ? xEnv
1418
0
                            : uno::Reference< ucb::XCommandEnvironment >(),
1419
0
                        u"Got no data stream!"_ustr,
1420
0
                        this );
1421
                    // Unreachable
1422
0
                }
1423
1424
0
                try
1425
0
                {
1426
0
                    uno::Sequence< sal_Int8 > aBuffer;
1427
1428
0
                    while (true)
1429
0
                    {
1430
0
                        sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1431
0
                        if (!nRead)
1432
0
                            break;
1433
0
                        aBuffer.realloc( nRead );
1434
0
                        xOut->writeBytes( aBuffer );
1435
0
                    }
1436
1437
0
                    xOut->closeOutput();
1438
0
                }
1439
0
                catch ( io::NotConnectedException const & )
1440
0
                {
1441
                    // closeOutput, readSomeBytes, writeBytes
1442
0
                }
1443
0
                catch ( io::BufferSizeExceededException const & )
1444
0
                {
1445
                    // closeOutput, readSomeBytes, writeBytes
1446
0
                }
1447
0
                catch ( io::IOException const & )
1448
0
                {
1449
                    // closeOutput, readSomeBytes, writeBytes
1450
0
                }
1451
0
            }
1452
0
            else
1453
0
            {
1454
0
                uno::Reference< io::XActiveDataSink > xDataSink(
1455
0
                                                rArg.Sink, uno::UNO_QUERY );
1456
0
                if ( xDataSink.is() )
1457
0
                {
1458
                    // PULL: wait for client read
1459
1460
                    // May throw CommandFailedException, DocumentPasswordRequest!
1461
0
                    uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1462
0
                    if ( !xIn.is() )
1463
0
                    {
1464
                        // No interaction if we are not persistent!
1465
0
                        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1466
0
                        {
1467
0
                            {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1468
0
                        }));
1469
0
                        ucbhelper::cancelCommandExecution(
1470
0
                            ucb::IOErrorCode_CANT_READ,
1471
0
                            aArgs,
1472
0
                            m_eState == PERSISTENT
1473
0
                                ? xEnv
1474
0
                                : uno::Reference<
1475
0
                                      ucb::XCommandEnvironment >(),
1476
0
                            u"Got no data stream!"_ustr,
1477
0
                            this );
1478
                        // Unreachable
1479
0
                    }
1480
1481
                    // Done.
1482
0
                    xDataSink->setInputStream( xIn );
1483
0
                }
1484
0
                else
1485
0
                {
1486
0
                    ucbhelper::cancelCommandExecution(
1487
0
                        uno::Any(
1488
0
                            ucb::UnsupportedDataSinkException(
1489
0
                                    OUString(),
1490
0
                                    getXWeak(),
1491
0
                                    rArg.Sink ) ),
1492
0
                        xEnv );
1493
                    // Unreachable
1494
0
                }
1495
0
            }
1496
0
        }
1497
0
    }
1498
1499
0
    return uno::Any();
1500
0
}
1501
1502
1503
void Content::insert( const uno::Reference< io::XInputStream >& xData,
1504
                      sal_Int32 nNameClashResolve,
1505
                      const uno::Reference<
1506
                          ucb::XCommandEnvironment > & xEnv )
1507
0
{
1508
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1509
1510
0
    ContentType eType = m_aProps.getType();
1511
1512
0
    OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1513
0
                "insert command only supported by streams and folders!" );
1514
1515
0
    Uri aUri( m_xIdentifier->getContentIdentifier() );
1516
1517
#if OSL_DEBUG_LEVEL > 0
1518
    if ( eType == STREAM )
1519
    {
1520
        Uri aParentUri( aUri.getParentUri() );
1521
        OSL_ENSURE( !aParentUri.isDocument(),
1522
                    "insert command not supported by streams that are direct "
1523
                    "children of document root!" );
1524
    }
1525
#endif
1526
1527
    // Check, if all required properties were set.
1528
0
    if ( eType == FOLDER )
1529
0
    {
1530
        // Required: Title
1531
1532
0
        if ( m_aProps.getTitle().isEmpty() )
1533
0
            m_aProps.setTitle( aUri.getDecodedName() );
1534
0
    }
1535
0
    else // stream
1536
0
    {
1537
        // Required: data
1538
1539
0
        if ( !xData.is() )
1540
0
        {
1541
0
            ucbhelper::cancelCommandExecution(
1542
0
                uno::Any( ucb::MissingInputStreamException(
1543
0
                                OUString(),
1544
0
                                getXWeak() ) ),
1545
0
                xEnv );
1546
            // Unreachable
1547
0
        }
1548
1549
        // Required: Title
1550
1551
0
        if ( m_aProps.getTitle().isEmpty() )
1552
0
            m_aProps.setTitle( aUri.getDecodedName() );
1553
0
    }
1554
1555
0
    Uri aNewUri( aUri.getParentUri() + m_aProps.getTitle() );
1556
1557
    // Handle possible name clash...
1558
0
    switch ( nNameClashResolve )
1559
0
    {
1560
        // fail.
1561
0
        case ucb::NameClash::ERROR:
1562
0
            if ( hasData( aNewUri ) )
1563
0
            {
1564
0
                ucbhelper::cancelCommandExecution(
1565
0
                    uno::Any( ucb::NameClashException(
1566
0
                                    OUString(),
1567
0
                                    getXWeak(),
1568
0
                                    task::InteractionClassification_ERROR,
1569
0
                                    m_aProps.getTitle() ) ),
1570
0
                    xEnv );
1571
                // Unreachable
1572
0
            }
1573
0
            break;
1574
1575
        // replace (possibly) existing object.
1576
0
        case ucb::NameClash::OVERWRITE:
1577
0
            break;
1578
1579
        // "invent" a new valid title.
1580
0
        case ucb::NameClash::RENAME:
1581
0
            if ( hasData( aNewUri ) )
1582
0
            {
1583
0
                sal_Int32 nTry = 0;
1584
1585
0
                do
1586
0
                {
1587
0
                    aNewUri.setUri( aNewUri.getUri() + "_" + OUString::number(++nTry) );
1588
0
                }
1589
0
                while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1590
1591
0
                if ( nTry == 1000 )
1592
0
                {
1593
0
                    ucbhelper::cancelCommandExecution(
1594
0
                        uno::Any(
1595
0
                            ucb::UnsupportedNameClashException(
1596
0
                                u"Unable to resolve name clash!"_ustr,
1597
0
                                getXWeak(),
1598
0
                                nNameClashResolve ) ),
1599
0
                        xEnv );
1600
                    // Unreachable
1601
0
                }
1602
0
                else
1603
0
                {
1604
0
                    m_aProps.setTitle( m_aProps.getTitle() + "_" + OUString::number( ++nTry ) );
1605
0
                }
1606
0
            }
1607
0
            break;
1608
1609
0
        case ucb::NameClash::KEEP: // deprecated
1610
0
        case ucb::NameClash::ASK:
1611
0
        default:
1612
0
            if ( hasData( aNewUri ) )
1613
0
            {
1614
0
                ucbhelper::cancelCommandExecution(
1615
0
                    uno::Any(
1616
0
                        ucb::UnsupportedNameClashException(
1617
0
                            OUString(),
1618
0
                            getXWeak(),
1619
0
                            nNameClashResolve ) ),
1620
0
                    xEnv );
1621
                // Unreachable
1622
0
            }
1623
0
            break;
1624
0
    }
1625
1626
    // Identifier changed?
1627
0
    bool bNewId = ( aUri != aNewUri );
1628
1629
0
    if ( bNewId )
1630
0
    {
1631
0
        m_xIdentifier
1632
0
            = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1633
0
    }
1634
1635
0
    if ( !storeData( xData, xEnv ) )
1636
0
    {
1637
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1638
0
        {
1639
0
            {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1640
0
        }));
1641
0
        ucbhelper::cancelCommandExecution(
1642
0
            ucb::IOErrorCode_CANT_WRITE,
1643
0
            aArgs,
1644
0
            xEnv,
1645
0
            u"Cannot store persistent data!"_ustr,
1646
0
            this );
1647
        // Unreachable
1648
0
    }
1649
1650
0
    m_eState = PERSISTENT;
1651
1652
0
    if ( bNewId )
1653
0
    {
1654
        //loadData( m_pProvider, m_aUri, m_aProps );
1655
1656
0
        aGuard.clear();
1657
0
        inserted();
1658
0
    }
1659
0
}
1660
1661
1662
void Content::destroy( bool bDeletePhysical,
1663
                       const uno::Reference<
1664
                           ucb::XCommandEnvironment > & xEnv )
1665
0
{
1666
    // @@@ take care about bDeletePhysical -> trashcan support
1667
1668
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1669
1670
0
    ContentType eType = m_aProps.getType();
1671
1672
0
    OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1673
0
                "delete command only supported by streams and folders!" );
1674
1675
0
    uno::Reference< ucb::XContent > xThis = this;
1676
1677
    // Persistent?
1678
0
    if ( m_eState != PERSISTENT )
1679
0
    {
1680
0
        ucbhelper::cancelCommandExecution(
1681
0
            uno::Any( ucb::UnsupportedCommandException(
1682
0
                                u"Not persistent!"_ustr,
1683
0
                                getXWeak() ) ),
1684
0
            xEnv );
1685
        // Unreachable
1686
0
    }
1687
1688
0
    m_eState = DEAD;
1689
1690
0
    aGuard.clear();
1691
0
    deleted();
1692
1693
0
    if ( eType == FOLDER )
1694
0
    {
1695
        // Process instantiated children...
1696
1697
0
        ContentRefList aChildren;
1698
0
        queryChildren( aChildren );
1699
1700
0
        for ( auto& rChild : aChildren )
1701
0
        {
1702
0
            rChild->destroy( bDeletePhysical, xEnv );
1703
0
        }
1704
0
    }
1705
0
}
1706
1707
1708
void Content::notifyDocumentClosed()
1709
0
{
1710
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1711
1712
0
    m_eState = DEAD;
1713
1714
    // @@@ anything else to reset or such?
1715
1716
    // callback follows!
1717
0
    aGuard.clear();
1718
1719
    // Propagate destruction to content event listeners
1720
    // Remove this from provider's content list.
1721
0
    deleted();
1722
0
}
1723
1724
1725
uno::Reference< ucb::XContent >
1726
Content::queryChildContent( std::u16string_view rRelativeChildUri )
1727
0
{
1728
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
1729
1730
0
    const OUString aMyId = getIdentifier()->getContentIdentifier();
1731
0
    OUStringBuffer aBuf( aMyId );
1732
0
    if ( !aMyId.endsWith("/") )
1733
0
        aBuf.append( "/" );
1734
0
    if ( !o3tl::starts_with(rRelativeChildUri, u"/") )
1735
0
        aBuf.append( rRelativeChildUri );
1736
0
    else
1737
0
        aBuf.append( rRelativeChildUri.substr(1) );
1738
1739
0
    uno::Reference< ucb::XContentIdentifier > xChildId
1740
0
        = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1741
1742
0
    uno::Reference< ucb::XContent > xChild;
1743
0
    try
1744
0
    {
1745
0
        xChild = m_pProvider->queryContent( xChildId );
1746
0
    }
1747
0
    catch ( ucb::IllegalIdentifierException const & )
1748
0
    {
1749
        // handled below.
1750
0
    }
1751
1752
0
    OSL_ENSURE( xChild.is(),
1753
0
                "Content::queryChildContent - unable to create child content!" );
1754
0
    return xChild;
1755
0
}
1756
1757
1758
void Content::notifyChildRemoved( std::u16string_view rRelativeChildUri )
1759
0
{
1760
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1761
1762
    // Ugly! Need to create child content object, just to fill event properly.
1763
0
    uno::Reference< ucb::XContent > xChild
1764
0
        = queryChildContent( rRelativeChildUri );
1765
1766
0
    if ( !xChild.is() )
1767
0
        return;
1768
1769
    // callback follows!
1770
0
    aGuard.clear();
1771
1772
    // Notify "REMOVED" event.
1773
0
    ucb::ContentEvent aEvt(
1774
0
        getXWeak(),
1775
0
        ucb::ContentAction::REMOVED,
1776
0
        xChild,
1777
0
        getIdentifier() );
1778
0
    notifyContentEvent( aEvt );
1779
0
}
1780
1781
1782
void Content::notifyChildInserted( std::u16string_view rRelativeChildUri )
1783
0
{
1784
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1785
1786
    // Ugly! Need to create child content object, just to fill event properly.
1787
0
    uno::Reference< ucb::XContent > xChild
1788
0
        = queryChildContent( rRelativeChildUri );
1789
1790
0
    if ( !xChild.is() )
1791
0
        return;
1792
1793
    // callback follows!
1794
0
    aGuard.clear();
1795
1796
    // Notify "INSERTED" event.
1797
0
    ucb::ContentEvent aEvt(
1798
0
        getXWeak(),
1799
0
        ucb::ContentAction::INSERTED,
1800
0
        xChild,
1801
0
        getIdentifier() );
1802
0
    notifyContentEvent( aEvt );
1803
0
}
1804
1805
1806
void Content::transfer(
1807
            const ucb::TransferInfo& rInfo,
1808
            const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1809
0
{
1810
0
    osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1811
1812
    // Persistent?
1813
0
    if ( m_eState != PERSISTENT )
1814
0
    {
1815
0
        ucbhelper::cancelCommandExecution(
1816
0
            uno::Any( ucb::UnsupportedCommandException(
1817
0
                                u"Not persistent!"_ustr,
1818
0
                                getXWeak() ) ),
1819
0
            xEnv );
1820
        // Unreachable
1821
0
    }
1822
1823
    // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1824
1825
0
    if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1826
0
    {
1827
        // Invalid length (to short).
1828
0
        ucbhelper::cancelCommandExecution(
1829
0
            uno::Any( ucb::InteractiveBadTransferURLException(
1830
0
                            OUString(),
1831
0
                            getXWeak() ) ),
1832
0
            xEnv );
1833
        // Unreachable
1834
0
    }
1835
1836
0
    OUString aScheme
1837
0
        = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1838
0
            .toAsciiLowerCase();
1839
0
    if ( aScheme != TDOC_URL_SCHEME ":/" )
1840
0
    {
1841
        // Invalid scheme.
1842
0
        ucbhelper::cancelCommandExecution(
1843
0
            uno::Any( ucb::InteractiveBadTransferURLException(
1844
0
                            OUString(),
1845
0
                            getXWeak() ) ),
1846
0
            xEnv );
1847
        // Unreachable
1848
0
    }
1849
1850
    // Does source URI describe a tdoc folder or stream?
1851
0
    Uri aSourceUri( rInfo.SourceURL );
1852
0
    if ( !aSourceUri.isValid() )
1853
0
    {
1854
0
        ucbhelper::cancelCommandExecution(
1855
0
            uno::Any( lang::IllegalArgumentException(
1856
0
                                u"Invalid source URI! Syntax!"_ustr,
1857
0
                                getXWeak(),
1858
0
                                -1 ) ),
1859
0
            xEnv );
1860
        // Unreachable
1861
0
    }
1862
1863
0
    if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1864
0
    {
1865
0
        ucbhelper::cancelCommandExecution(
1866
0
            uno::Any( lang::IllegalArgumentException(
1867
0
                                u"Invalid source URI! Must describe a folder or stream!"_ustr,
1868
0
                                getXWeak(),
1869
0
                                -1 ) ),
1870
0
            xEnv );
1871
        // Unreachable
1872
0
    }
1873
1874
    // Is source not a parent of me / not me?
1875
0
    OUString aId = m_xIdentifier->getContentIdentifier();
1876
0
    sal_Int32 nPos = aId.lastIndexOf( '/' );
1877
0
    if ( nPos != ( aId.getLength() - 1 ) )
1878
0
    {
1879
        // No trailing slash found. Append.
1880
0
        aId += "/";
1881
0
    }
1882
1883
0
    if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1884
0
    {
1885
0
        if ( aId.startsWith( rInfo.SourceURL ) )
1886
0
        {
1887
0
            uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1888
0
            {
1889
0
                {"Uri", uno::Any(rInfo.SourceURL)}
1890
0
            }));
1891
0
            ucbhelper::cancelCommandExecution(
1892
0
                ucb::IOErrorCode_RECURSIVE,
1893
0
                aArgs,
1894
0
                xEnv,
1895
0
                u"Target is equal to or is a child of source!"_ustr,
1896
0
                this );
1897
            // Unreachable
1898
0
        }
1899
0
    }
1900
1901
0
    if ( m_aProps.getType() == DOCUMENT )
1902
0
    {
1903
0
        bool bOK = false;
1904
1905
0
        uno::Reference< embed::XStorage > xStorage
1906
0
            = m_pProvider->queryStorage(
1907
0
                aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1908
0
        if ( xStorage.is() )
1909
0
        {
1910
0
            try
1911
0
            {
1912
0
                if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1913
0
                {
1914
0
                    ucbhelper::cancelCommandExecution(
1915
0
                        uno::Any( lang::IllegalArgumentException(
1916
0
                                        u"Invalid source URI! "
1917
0
                                        "Streams cannot be created as "
1918
0
                                        "children of document root!"_ustr,
1919
0
                                        getXWeak(),
1920
0
                                        -1 ) ),
1921
0
                        xEnv );
1922
                    // Unreachable
1923
0
                }
1924
0
                bOK = true;
1925
0
            }
1926
0
            catch ( container::NoSuchElementException const & )
1927
0
            {
1928
                // handled below.
1929
0
            }
1930
0
            catch ( lang::IllegalArgumentException const & )
1931
0
            {
1932
                // handled below.
1933
0
            }
1934
0
            catch ( embed::InvalidStorageException const & )
1935
0
            {
1936
                // handled below.
1937
0
            }
1938
0
        }
1939
1940
0
        if ( !bOK )
1941
0
        {
1942
0
            ucbhelper::cancelCommandExecution(
1943
0
                uno::Any( lang::IllegalArgumentException(
1944
0
                                    u"Invalid source URI! Unable to determine source type!"_ustr,
1945
0
                                    getXWeak(),
1946
0
                                    -1 ) ),
1947
0
                xEnv );
1948
            // Unreachable
1949
0
        }
1950
0
    }
1951
1952
1953
    // Copy data.
1954
1955
1956
0
    OUString aNewName( !rInfo.NewTitle.isEmpty()
1957
0
                                ? rInfo.NewTitle
1958
0
                                : aSourceUri.getDecodedName() );
1959
1960
0
    if ( !copyData( aSourceUri, aNewName ) )
1961
0
    {
1962
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1963
0
        {
1964
0
            {"Uri", uno::Any(rInfo.SourceURL)}
1965
0
        }));
1966
0
        ucbhelper::cancelCommandExecution(
1967
0
            ucb::IOErrorCode_CANT_WRITE,
1968
0
            aArgs,
1969
0
            xEnv,
1970
0
            u"Cannot copy data!"_ustr,
1971
0
            this );
1972
        // Unreachable
1973
0
    }
1974
1975
1976
    // Copy own and all children's Additional Core Properties.
1977
1978
1979
0
    OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1980
0
    if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1981
0
        aTargetUri += "/";
1982
1983
0
    if ( !rInfo.NewTitle.isEmpty() )
1984
0
        aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1985
0
    else
1986
0
        aTargetUri += aSourceUri.getName();
1987
1988
0
    if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1989
0
    {
1990
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1991
0
        {
1992
0
            {"Uri", uno::Any(rInfo.SourceURL)}
1993
0
        }));
1994
0
        ucbhelper::cancelCommandExecution(
1995
0
            ucb::IOErrorCode_CANT_WRITE,
1996
0
            aArgs,
1997
0
            xEnv,
1998
0
            u"Cannot copy additional properties!"_ustr,
1999
0
            this );
2000
        // Unreachable
2001
0
    }
2002
2003
2004
    // Propagate new content.
2005
2006
2007
0
    rtl::Reference< Content > xTarget;
2008
0
    try
2009
0
    {
2010
0
        uno::Reference< ucb::XContentIdentifier > xTargetId
2011
0
            = new ::ucbhelper::ContentIdentifier( aTargetUri );
2012
2013
        // Note: The static cast is okay here, because its sure that
2014
        //       m_xProvider is always the WebDAVContentProvider.
2015
0
        xTarget = static_cast< Content * >(
2016
0
            m_pProvider->queryContent( xTargetId ).get() );
2017
2018
0
    }
2019
0
    catch ( ucb::IllegalIdentifierException const & )
2020
0
    {
2021
        // queryContent
2022
0
    }
2023
2024
0
    if ( !xTarget.is() )
2025
0
    {
2026
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2027
0
        {
2028
0
            {"Uri", uno::Any(aTargetUri)}
2029
0
        }));
2030
0
        ucbhelper::cancelCommandExecution(
2031
0
            ucb::IOErrorCode_CANT_READ,
2032
0
            aArgs,
2033
0
            xEnv,
2034
0
            u"Cannot instantiate target object!"_ustr,
2035
0
            this );
2036
        // Unreachable
2037
0
    }
2038
2039
    // Announce transferred content in its new folder.
2040
0
    xTarget->inserted();
2041
2042
2043
    // Remove source, if requested
2044
2045
2046
0
    if ( !rInfo.MoveData )
2047
0
        return;
2048
2049
0
    rtl::Reference< Content > xSource;
2050
0
    try
2051
0
    {
2052
0
        uno::Reference< ucb::XContentIdentifier >
2053
0
            xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2054
2055
        // Note: The static cast is okay here, because its sure
2056
        //       that m_xProvider is always the ContentProvider.
2057
0
        xSource = static_cast< Content * >(
2058
0
            m_xProvider->queryContent( xSourceId ).get() );
2059
0
    }
2060
0
    catch ( ucb::IllegalIdentifierException const & )
2061
0
    {
2062
        // queryContent
2063
0
    }
2064
2065
0
    if ( !xSource.is() )
2066
0
    {
2067
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2068
0
        {
2069
0
            {"Uri", uno::Any(rInfo.SourceURL)}
2070
0
        }));
2071
0
        ucbhelper::cancelCommandExecution(
2072
0
            ucb::IOErrorCode_CANT_READ,
2073
0
            aArgs,
2074
0
            xEnv,
2075
0
            u"Cannot instantiate target object!"_ustr,
2076
0
            this );
2077
        // Unreachable
2078
0
    }
2079
2080
    // Propagate destruction (recursively).
2081
0
    xSource->destroy( true, xEnv );
2082
2083
    // Remove all persistent data of source and its children.
2084
0
    if ( !xSource->removeData() )
2085
0
    {
2086
0
        uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2087
0
        {
2088
0
            {"Uri", uno::Any(rInfo.SourceURL)}
2089
0
        }));
2090
0
        ucbhelper::cancelCommandExecution(
2091
0
            ucb::IOErrorCode_CANT_WRITE,
2092
0
            aArgs,
2093
0
            xEnv,
2094
0
            u"Cannot remove persistent data of source object!"_ustr,
2095
0
            this );
2096
        // Unreachable
2097
0
    }
2098
2099
    // Remove own and all children's Additional Core Properties.
2100
0
    if ( xSource->removeAdditionalPropertySet() )
2101
0
        return;
2102
2103
0
    uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2104
0
    {
2105
0
        {"Uri", uno::Any(rInfo.SourceURL)}
2106
0
    }));
2107
0
    ucbhelper::cancelCommandExecution(
2108
0
        ucb::IOErrorCode_CANT_WRITE,
2109
0
        aArgs,
2110
0
        xEnv,
2111
0
        u"Cannot remove additional properties of source object!"_ustr,
2112
0
        this );
2113
    // Unreachable
2114
0
}
2115
2116
2117
//static
2118
bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2119
0
{
2120
0
    if ( rUri.isRoot() )
2121
0
    {
2122
0
        return true; // root has no storage
2123
0
    }
2124
0
    else if ( rUri.isDocument() )
2125
0
    {
2126
0
        uno::Reference< embed::XStorage > xStorage
2127
0
            = pProvider->queryStorage( rUri.getUri(), READ );
2128
0
        return xStorage.is();
2129
0
    }
2130
0
    else
2131
0
    {
2132
        // folder or stream
2133
2134
        // Ask parent storage. In case that rUri describes a stream,
2135
        // ContentProvider::queryStorage( rUri ) would return null.
2136
2137
0
        uno::Reference< embed::XStorage > xStorage
2138
0
            = pProvider->queryStorage( rUri.getParentUri(), READ );
2139
2140
0
        if ( !xStorage.is() )
2141
0
            return false;
2142
2143
0
        return xStorage->hasByName( rUri.getDecodedName() );
2144
0
    }
2145
0
}
2146
2147
2148
//static
2149
bool Content::loadData( ContentProvider const * pProvider,
2150
                        const Uri & rUri,
2151
                        ContentProperties& rProps )
2152
4.00k
{
2153
4.00k
    if ( rUri.isRoot() ) // root has no storage, but can always be created
2154
0
    {
2155
0
        rProps
2156
0
            = ContentProperties(
2157
0
                ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2158
0
    }
2159
4.00k
    else if ( rUri.isDocument() ) // document must have storage
2160
4.00k
    {
2161
4.00k
        uno::Reference< embed::XStorage > xStorage
2162
4.00k
            = pProvider->queryStorage( rUri.getUri(), READ );
2163
2164
4.00k
        if ( !xStorage.is() )
2165
4.00k
            return false;
2166
2167
0
        rProps
2168
0
            = ContentProperties(
2169
0
                DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2170
0
    }
2171
0
    else // stream or folder; stream has no storage; folder has storage
2172
0
    {
2173
0
        uno::Reference< embed::XStorage > xStorage
2174
0
            = pProvider->queryStorage( rUri.getParentUri(), READ );
2175
2176
0
        if ( !xStorage.is() )
2177
0
            return false;
2178
2179
        // Check whether exists at all, is stream or folder
2180
0
        try
2181
0
        {
2182
            // return: true  -> folder
2183
            // return: false -> stream
2184
            // NoSuchElementException -> neither folder nor stream
2185
0
            bool bIsFolder
2186
0
                = xStorage->isStorageElement( rUri.getDecodedName() );
2187
2188
0
            rProps
2189
0
                = ContentProperties(
2190
0
                    bIsFolder ? FOLDER : STREAM,
2191
0
                    pProvider->queryStorageTitle( rUri.getUri() ) );
2192
0
        }
2193
0
        catch ( container::NoSuchElementException const & )
2194
0
        {
2195
            // there is no element with such name
2196
            //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2197
0
            return false;
2198
0
        }
2199
0
        catch ( lang::IllegalArgumentException const & )
2200
0
        {
2201
            // an illegal argument is provided
2202
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2203
0
            return false;
2204
0
        }
2205
0
        catch ( embed::InvalidStorageException const & )
2206
0
        {
2207
            // this storage is in invalid state for any reason
2208
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2209
0
            return false;
2210
0
        }
2211
0
    }
2212
0
    return true;
2213
4.00k
}
2214
2215
2216
bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2217
                         const uno::Reference<
2218
                            ucb::XCommandEnvironment >& xEnv )
2219
0
{
2220
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
2221
2222
0
    ContentType eType = m_aProps.getType();
2223
0
    if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2224
0
    {
2225
0
        OSL_FAIL( "storeData not supported by root and documents!" );
2226
0
        return false;
2227
0
    }
2228
2229
0
    Uri aUri( m_xIdentifier->getContentIdentifier() );
2230
2231
0
    if ( eType == FOLDER )
2232
0
    {
2233
0
        uno::Reference< embed::XStorage > xStorage
2234
0
            = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2235
2236
0
        if ( !xStorage.is() )
2237
0
            return false;
2238
2239
0
        uno::Reference< beans::XPropertySet > xPropSet(
2240
0
            xStorage, uno::UNO_QUERY );
2241
0
        OSL_ENSURE( xPropSet.is(),
2242
0
                    "Content::storeData - Got no XPropertySet interface!" );
2243
0
        if ( !xPropSet.is() )
2244
0
            return false;
2245
2246
0
        try
2247
0
        {
2248
            // According to MBA, if no mediatype is set, folder and all
2249
            // its contents will be lost on save of the document!!!
2250
0
            xPropSet->setPropertyValue(
2251
0
                u"MediaType"_ustr,
2252
0
                uno::Any(
2253
0
                    u"application/binary"_ustr ) );
2254
0
        }
2255
0
        catch ( beans::UnknownPropertyException const & )
2256
0
        {
2257
0
            OSL_FAIL( "Property MediaType not supported!" );
2258
0
            return false;
2259
0
        }
2260
0
        catch ( beans::PropertyVetoException const & )
2261
0
        {
2262
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2263
0
            return false;
2264
0
        }
2265
0
        catch ( lang::IllegalArgumentException const & )
2266
0
        {
2267
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2268
0
            return false;
2269
0
        }
2270
0
        catch ( lang::WrappedTargetException const & )
2271
0
        {
2272
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2273
0
            return false;
2274
0
        }
2275
2276
0
        if ( !commitStorage( xStorage ) )
2277
0
            return false;
2278
0
    }
2279
0
    else if ( eType == STREAM )
2280
0
    {
2281
        // stream
2282
2283
        // Important: Parent storage and output stream must be kept alive until
2284
        //            changes have been committed!
2285
0
        uno::Reference< embed::XStorage > xStorage
2286
0
            = m_pProvider->queryStorage(
2287
0
                aUri.getParentUri(), READ_WRITE_CREATE );
2288
0
        uno::Reference< io::XOutputStream > xOut;
2289
2290
0
        if ( !xStorage.is() )
2291
0
            return false;
2292
2293
0
        if ( xData.is() )
2294
0
        {
2295
            // May throw CommandFailedException, DocumentPasswordRequest!
2296
0
            xOut = getTruncatedOutputStream( xEnv );
2297
2298
0
            OSL_ENSURE( xOut.is(), "No target data stream!" );
2299
2300
0
            try
2301
0
            {
2302
0
                uno::Sequence< sal_Int8 > aBuffer;
2303
0
                while (true)
2304
0
                {
2305
0
                    sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2306
0
                    if (!nRead)
2307
0
                        break;
2308
0
                    aBuffer.realloc( nRead );
2309
0
                    xOut->writeBytes( aBuffer );
2310
0
                }
2311
2312
0
                closeOutputStream( xOut );
2313
0
            }
2314
0
            catch ( io::NotConnectedException const & )
2315
0
            {
2316
                // readSomeBytes, writeBytes
2317
0
                TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2318
0
                closeOutputStream( xOut );
2319
0
                return false;
2320
0
            }
2321
0
            catch ( io::BufferSizeExceededException const & )
2322
0
            {
2323
                // readSomeBytes, writeBytes
2324
0
                TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2325
0
                closeOutputStream( xOut );
2326
0
                return false;
2327
0
            }
2328
0
            catch ( io::IOException const & )
2329
0
            {
2330
                // readSomeBytes, writeBytes
2331
0
                TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2332
0
                closeOutputStream( xOut );
2333
0
                return false;
2334
0
            }
2335
0
            catch ( ... )
2336
0
            {
2337
0
                closeOutputStream( xOut );
2338
0
                throw;
2339
0
            }
2340
0
        }
2341
2342
        // Commit changes.
2343
0
        if ( !commitStorage( xStorage ) )
2344
0
            return false;
2345
0
    }
2346
0
    else
2347
0
    {
2348
0
        OSL_FAIL( "Unknown content type!" );
2349
0
        return false;
2350
0
    }
2351
0
    return true;
2352
0
}
2353
2354
2355
void Content::renameData(
2356
            const uno::Reference< ucb::XContentIdentifier >& xOldId,
2357
            const uno::Reference< ucb::XContentIdentifier >& xNewId )
2358
0
{
2359
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
2360
2361
0
    ContentType eType = m_aProps.getType();
2362
0
    if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2363
0
    {
2364
0
        OSL_FAIL( "renameData not supported by root and documents!" );
2365
0
        return;
2366
0
    }
2367
2368
0
    Uri aOldUri( xOldId->getContentIdentifier() );
2369
0
    uno::Reference< embed::XStorage > xStorage
2370
0
        = m_pProvider->queryStorage(
2371
0
            aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2372
2373
0
    if ( !xStorage.is() )
2374
0
        return;
2375
2376
0
    try
2377
0
    {
2378
0
        Uri aNewUri( xNewId->getContentIdentifier() );
2379
0
        xStorage->renameElement(
2380
0
            aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2381
0
    }
2382
0
    catch ( embed::InvalidStorageException const & )
2383
0
    {
2384
        // this storage is in invalid state for any reason
2385
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2386
0
        return;
2387
0
    }
2388
0
    catch ( lang::IllegalArgumentException const & )
2389
0
    {
2390
        // an illegal argument is provided
2391
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2392
0
        return;
2393
0
    }
2394
0
    catch ( container::NoSuchElementException const & )
2395
0
    {
2396
        // there is no element with old name in this storage
2397
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2398
0
        return;
2399
0
    }
2400
0
    catch ( container::ElementExistException const & )
2401
0
    {
2402
        // an element with new name already exists in this storage
2403
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2404
0
        return;
2405
0
    }
2406
0
    catch ( io::IOException const & )
2407
0
    {
2408
        // in case of io errors during renaming
2409
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2410
0
        return;
2411
0
    }
2412
0
    catch ( embed::StorageWrappedTargetException const & )
2413
0
    {
2414
        // wraps other exceptions
2415
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2416
0
        return;
2417
0
    }
2418
2419
0
    commitStorage( xStorage );
2420
0
}
2421
2422
2423
bool Content::removeData()
2424
0
{
2425
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
2426
2427
0
    ContentType eType = m_aProps.getType();
2428
0
    if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2429
0
    {
2430
0
        OSL_FAIL( "removeData not supported by root and documents!" );
2431
0
        return false;
2432
0
    }
2433
2434
0
    Uri aUri( m_xIdentifier->getContentIdentifier() );
2435
0
    uno::Reference< embed::XStorage > xStorage
2436
0
        = m_pProvider->queryStorage(
2437
0
            aUri.getParentUri(), READ_WRITE_NOCREATE );
2438
2439
0
    if ( !xStorage.is() )
2440
0
        return false;
2441
2442
0
    try
2443
0
    {
2444
0
        xStorage->removeElement( aUri.getDecodedName() );
2445
0
    }
2446
0
    catch ( embed::InvalidStorageException const & )
2447
0
    {
2448
        // this storage is in invalid state for any reason
2449
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2450
0
        return false;
2451
0
    }
2452
0
    catch ( lang::IllegalArgumentException const & )
2453
0
    {
2454
        // an illegal argument is provided
2455
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2456
0
        return false;
2457
0
    }
2458
0
    catch ( container::NoSuchElementException const & )
2459
0
    {
2460
        // there is no element with this name in this storage
2461
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2462
0
        return false;
2463
0
    }
2464
0
    catch ( io::IOException const & )
2465
0
    {
2466
        // in case of io errors during renaming
2467
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2468
0
        return false;
2469
0
    }
2470
0
    catch ( embed::StorageWrappedTargetException const & )
2471
0
    {
2472
        // wraps other exceptions
2473
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2474
0
        return false;
2475
0
    }
2476
2477
0
    return commitStorage( xStorage );
2478
0
}
2479
2480
2481
bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2482
0
{
2483
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
2484
2485
0
    ContentType eType = m_aProps.getType();
2486
0
    if ( ( eType == ROOT ) || ( eType == STREAM ) )
2487
0
    {
2488
0
        OSL_FAIL( "copyData not supported by root and streams!" );
2489
0
        return false;
2490
0
    }
2491
2492
0
    Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2493
0
    uno::Reference< embed::XStorage > xDestStorage
2494
0
        = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2495
2496
0
    if ( !xDestStorage.is() )
2497
0
        return false;
2498
2499
0
    uno::Reference< embed::XStorage > xSourceStorage
2500
0
        = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2501
2502
0
    if ( !xSourceStorage.is() )
2503
0
        return false;
2504
2505
0
    try
2506
0
    {
2507
0
        xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2508
0
                                       xDestStorage,
2509
0
                                       rNewName );
2510
0
    }
2511
0
    catch ( embed::InvalidStorageException const & )
2512
0
    {
2513
        // this storage is in invalid state for any reason
2514
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2515
0
        return false;
2516
0
    }
2517
0
    catch ( lang::IllegalArgumentException const & )
2518
0
    {
2519
        // an illegal argument is provided
2520
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2521
0
        return false;
2522
0
    }
2523
0
    catch ( container::NoSuchElementException const & )
2524
0
    {
2525
        // there is no element with this name in this storage
2526
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2527
0
        return false;
2528
0
    }
2529
0
    catch ( container::ElementExistException const & )
2530
0
    {
2531
        // there is no element with this name in this storage
2532
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2533
0
        return false;
2534
0
    }
2535
0
    catch ( io::IOException const & )
2536
0
    {
2537
        // in case of io errors during renaming
2538
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2539
0
        return false;
2540
0
    }
2541
0
    catch ( embed::StorageWrappedTargetException const & )
2542
0
    {
2543
        // wraps other exceptions
2544
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2545
0
        return false;
2546
0
    }
2547
2548
0
    return commitStorage( xDestStorage );
2549
0
}
2550
2551
2552
// static
2553
bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2554
0
{
2555
    // Commit changes
2556
0
    uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2557
2558
0
    OSL_ENSURE( xTO.is(),
2559
0
                "Required interface css.embed.XTransactedObject missing!" );
2560
0
    try
2561
0
    {
2562
0
        xTO->commit();
2563
0
    }
2564
0
    catch ( io::IOException const & )
2565
0
    {
2566
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2567
0
        return false;
2568
0
    }
2569
0
    catch ( lang::WrappedTargetException const & )
2570
0
    {
2571
0
        TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2572
0
        return false;
2573
0
    }
2574
2575
0
    return true;
2576
0
}
2577
2578
2579
// static
2580
bool Content::closeOutputStream(
2581
    const uno::Reference< io::XOutputStream > & xOut )
2582
0
{
2583
0
    if ( xOut.is() )
2584
0
    {
2585
0
        try
2586
0
        {
2587
0
            xOut->closeOutput();
2588
0
            return true;
2589
0
        }
2590
0
        catch ( io::NotConnectedException const & )
2591
0
        {
2592
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2593
0
        }
2594
0
        catch ( io::BufferSizeExceededException const & )
2595
0
        {
2596
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2597
0
        }
2598
0
        catch ( io::IOException const & )
2599
0
        {
2600
0
            TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2601
0
        }
2602
0
    }
2603
0
    return false;
2604
0
}
2605
2606
/// @throws ucb::CommandFailedException
2607
/// @throws task::DocumentPasswordRequest
2608
static OUString obtainPassword(
2609
        const OUString & rName,
2610
        task::PasswordRequestMode eMode,
2611
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2612
0
{
2613
0
    rtl::Reference< DocumentPasswordRequest > xRequest
2614
0
        = new DocumentPasswordRequest( eMode, rName );
2615
2616
0
    if ( xEnv.is() )
2617
0
    {
2618
0
        uno::Reference< task::XInteractionHandler > xIH
2619
0
            = xEnv->getInteractionHandler();
2620
0
        if ( xIH.is() )
2621
0
        {
2622
0
            xIH->handle( xRequest );
2623
2624
0
            rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2625
0
                = xRequest->getSelection();
2626
2627
0
            if ( xSelection.is() )
2628
0
            {
2629
                // Handler handled the request.
2630
0
                uno::Reference< task::XInteractionAbort > xAbort(
2631
0
                    xSelection->getXWeak(), uno::UNO_QUERY );
2632
0
                if ( xAbort.is() )
2633
0
                {
2634
0
                    throw ucb::CommandFailedException(
2635
0
                        u"Abort requested by Interaction Handler."_ustr,
2636
0
                        uno::Reference< uno::XInterface >(),
2637
0
                        xRequest->getRequest() );
2638
0
                }
2639
2640
0
                uno::Reference< task::XInteractionPassword > xPassword(
2641
0
                    xSelection->getXWeak(), uno::UNO_QUERY );
2642
0
                if ( xPassword.is() )
2643
0
                {
2644
0
                    return xPassword->getPassword();
2645
0
                }
2646
2647
                // Unknown selection. Should never happen.
2648
0
                throw ucb::CommandFailedException(
2649
0
                    u"Interaction Handler selected unknown continuation!"_ustr,
2650
0
                    uno::Reference< uno::XInterface >(),
2651
0
                    xRequest->getRequest() );
2652
0
            }
2653
0
        }
2654
0
    }
2655
2656
    // No IH or IH did not handle exception.
2657
0
    task::DocumentPasswordRequest aRequest;
2658
0
    xRequest->getRequest() >>= aRequest;
2659
0
    throw aRequest;
2660
0
}
2661
2662
2663
uno::Reference< io::XInputStream > Content::getInputStream(
2664
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2665
0
{
2666
0
    OUString aUri;
2667
0
    OUString aPassword;
2668
0
    bool bPasswordRequested = false;
2669
2670
0
    {
2671
0
        osl::Guard< osl::Mutex > aGuard( m_aMutex );
2672
2673
0
        OSL_ENSURE( m_aProps.getType() == STREAM,
2674
0
                    "Content::getInputStream - content is no stream!" );
2675
2676
0
        aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2677
0
    }
2678
2679
0
    for ( ;; )
2680
0
    {
2681
0
        try
2682
0
        {
2683
0
            osl::Guard< osl::Mutex > aGuard( m_aMutex );
2684
0
            return m_pProvider->queryInputStream( aUri, aPassword );
2685
0
        }
2686
0
        catch ( packages::WrongPasswordException const & )
2687
0
        {
2688
            // Obtain (new) password.
2689
0
            aPassword
2690
0
                = obtainPassword( aUri, /* @@@ find better title */
2691
0
                                  bPasswordRequested
2692
0
                                   ? task::PasswordRequestMode_PASSWORD_REENTER
2693
0
                                   : task::PasswordRequestMode_PASSWORD_ENTER,
2694
0
                                   xEnv );
2695
0
            bPasswordRequested = true;
2696
0
        }
2697
0
    }
2698
0
}
2699
2700
/// @throws ucb::CommandFailedException
2701
/// @throws task::DocumentPasswordRequest
2702
/// @throws uno::RuntimeException
2703
static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2704
                const OUString & rUri,
2705
                ContentProvider const * pProvider,
2706
                const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2707
0
{
2708
0
    OUString aPassword;
2709
0
    bool bPasswordRequested = false;
2710
0
    for ( ;; )
2711
0
    {
2712
0
        try
2713
0
        {
2714
0
            return pProvider->queryOutputStream(
2715
0
                    rUri, aPassword, true /* truncate */ );
2716
0
        }
2717
0
        catch ( packages::WrongPasswordException const & )
2718
0
        {
2719
            // Obtain (new) password.
2720
0
            aPassword
2721
0
                = obtainPassword( rUri, /* @@@ find better title */
2722
0
                                  bPasswordRequested
2723
0
                                   ? task::PasswordRequestMode_PASSWORD_REENTER
2724
0
                                   : task::PasswordRequestMode_PASSWORD_ENTER,
2725
0
                                   xEnv );
2726
0
            bPasswordRequested = true;
2727
0
        }
2728
0
    }
2729
0
}
2730
2731
2732
uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2733
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2734
0
{
2735
0
    OSL_ENSURE( m_aProps.getType() == STREAM,
2736
0
                "Content::getTruncatedOutputStream - content is no stream!" );
2737
2738
0
    return lcl_getTruncatedOutputStream(
2739
0
            Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2740
0
            m_pProvider,
2741
0
            xEnv );
2742
0
}
2743
2744
2745
uno::Reference< io::XStream > Content::getStream(
2746
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2747
0
{
2748
0
    osl::Guard< osl::Mutex > aGuard( m_aMutex );
2749
2750
0
    OSL_ENSURE( m_aProps.getType() == STREAM,
2751
0
                "Content::getStream - content is no stream!" );
2752
2753
0
    OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2754
0
    OUString aPassword;
2755
0
    bool bPasswordRequested = false;
2756
0
    for ( ;; )
2757
0
    {
2758
0
        try
2759
0
        {
2760
0
            return m_pProvider->queryStream(
2761
0
                    aUri, aPassword, false /* no truncate */ );
2762
0
        }
2763
0
        catch ( packages::WrongPasswordException const & )
2764
0
        {
2765
            // Obtain (new) password.
2766
0
            aPassword
2767
0
                = obtainPassword( aUri, /* @@@ find better title */
2768
0
                                  bPasswordRequested
2769
0
                                   ? task::PasswordRequestMode_PASSWORD_REENTER
2770
0
                                   : task::PasswordRequestMode_PASSWORD_ENTER,
2771
0
                                   xEnv );
2772
0
            bPasswordRequested = true;
2773
0
        }
2774
0
    }
2775
0
}
2776
2777
2778
// ContentProperties Implementation.
2779
2780
2781
uno::Sequence< ucb::ContentInfo >
2782
ContentProperties::getCreatableContentsInfo() const
2783
0
{
2784
0
    if ( isContentCreator() )
2785
0
    {
2786
0
        uno::Sequence< beans::Property > aProps( 1 );
2787
0
        aProps.getArray()[ 0 ] = beans::Property(
2788
0
                    u"Title"_ustr,
2789
0
                    -1,
2790
0
                    cppu::UnoType<OUString>::get(),
2791
0
                    beans::PropertyAttribute::BOUND );
2792
2793
0
        if ( getType() == DOCUMENT )
2794
0
        {
2795
            // streams cannot be created as direct children of document root
2796
0
            uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2797
2798
            // Folder.
2799
0
            aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2800
0
            aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2801
0
            aSeq.getArray()[ 0 ].Properties = std::move(aProps);
2802
2803
0
            return aSeq;
2804
0
        }
2805
0
        else
2806
0
        {
2807
0
            uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2808
2809
            // Folder.
2810
0
            aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2811
0
            aSeq.getArray()[ 0 ].Attributes
2812
0
                = ucb::ContentInfoAttribute::KIND_FOLDER;
2813
0
            aSeq.getArray()[ 0 ].Properties = aProps;
2814
2815
            // Stream.
2816
0
            aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2817
0
            aSeq.getArray()[ 1 ].Attributes
2818
0
                = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2819
0
                  | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2820
0
            aSeq.getArray()[ 1 ].Properties = std::move(aProps);
2821
2822
0
            return aSeq;
2823
0
        }
2824
0
    }
2825
0
    else
2826
0
    {
2827
0
        OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2828
0
                    "object!" );
2829
2830
0
        return uno::Sequence< ucb::ContentInfo >( 0 );
2831
0
    }
2832
0
}
2833
2834
2835
bool ContentProperties::isContentCreator() const
2836
0
{
2837
0
    return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2838
0
}
2839
2840
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */