tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / ucb / source / core / ucb.cxx
blob43e5ca0ab09655bde262620d014bc3c008793c64
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
27 #include <sal/config.h>
29 #include <string_view>
31 #include <osl/diagnose.h>
32 #include <sal/log.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/propertysequence.hxx>
36 #include <com/sun/star/lang/IllegalArgumentException.hpp>
37 #include <com/sun/star/ucb/DuplicateProviderException.hpp>
38 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
39 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
40 #include <com/sun/star/ucb/XCommandInfo.hpp>
41 #include <com/sun/star/ucb/XContentProviderSupplier.hpp>
42 #include <com/sun/star/configuration/theDefaultProvider.hpp>
43 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/uno/Any.hxx>
46 #include <cppuhelper/supportsservice.hxx>
47 #include <cppuhelper/weak.hxx>
48 #include <ucbhelper/cancelcommandexecution.hxx>
49 #include <comphelper/diagnose_ex.hxx>
50 #include "identify.hxx"
51 #include "ucbcmds.hxx"
53 #include "ucb.hxx"
55 using namespace comphelper;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::lang;
58 using namespace com::sun::star::ucb;
59 using namespace ucb_impl;
60 using namespace com::sun::star;
61 using namespace ucbhelper;
63 namespace {
65 bool fillPlaceholders(OUString const & rInput,
66 uno::Sequence< uno::Any > const & rReplacements,
67 OUString * pOutput)
69 sal_Unicode const * p = rInput.getStr();
70 sal_Unicode const * pEnd = p + rInput.getLength();
71 sal_Unicode const * pCopy = p;
72 OUStringBuffer aBuffer;
73 while (p != pEnd)
74 switch (*p++)
76 case '&':
77 if (pEnd - p >= 4
78 && p[0] == 'a' && p[1] == 'm' && p[2] == 'p'
79 && p[3] == ';')
81 aBuffer.append(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + "&");
82 p += 4;
83 pCopy = p;
85 else if (pEnd - p >= 3
86 && p[0] == 'l' && p[1] == 't' && p[2] == ';')
88 aBuffer.append(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + "<");
89 p += 3;
90 pCopy = p;
92 else if (pEnd - p >= 3
93 && p[0] == 'g' && p[1] == 't' && p[2] == ';')
95 aBuffer.append(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + ">");
96 p += 3;
97 pCopy = p;
99 break;
101 case '<':
102 sal_Unicode const * q = p;
103 while (q != pEnd && *q != '>')
104 ++q;
105 if (q == pEnd)
106 break;
107 OUString aKey(p, q - p);
108 OUString aValue;
109 bool bFound = false;
110 for (sal_Int32 i = 2; i + 1 < rReplacements.getLength();
111 i += 2)
113 OUString aReplaceKey;
114 if ((rReplacements[i] >>= aReplaceKey)
115 && aReplaceKey == aKey
116 && (rReplacements[i + 1] >>= aValue))
118 bFound = true;
119 break;
122 if (!bFound)
123 return false;
124 aBuffer.append(std::u16string_view(pCopy, p - 1 - pCopy) + aValue);
125 p = q + 1;
126 pCopy = p;
127 break;
129 aBuffer.append(pCopy, pEnd - pCopy);
130 *pOutput = aBuffer.makeStringAndClear();
131 return true;
134 void makeAndAppendXMLName(
135 OUStringBuffer & rBuffer, std::u16string_view rIn )
137 size_t nCount = rIn.size();
138 for ( size_t n = 0; n < nCount; ++n )
140 const sal_Unicode c = rIn[ n ];
141 switch ( c )
143 case '&':
144 rBuffer.append( "&amp;" );
145 break;
147 case '"':
148 rBuffer.append( "&quot;" );
149 break;
151 case '\'':
152 rBuffer.append( "&apos;" );
153 break;
155 case '<':
156 rBuffer.append( "&lt;" );
157 break;
159 case '>':
160 rBuffer.append( "&gt;" );
161 break;
163 default:
164 rBuffer.append( c );
165 break;
170 bool createContentProviderData(
171 std::u16string_view rProvider,
172 const uno::Reference< container::XHierarchicalNameAccess >& rxHierNameAccess,
173 ContentProviderData & rInfo)
175 // Obtain service name.
177 OUString aValue;
180 if ( !( rxHierNameAccess->getByHierarchicalName(
181 OUString::Concat(rProvider) + "/ServiceName" ) >>= aValue ) )
183 OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
184 "Error getting item value!" );
187 catch (const container::NoSuchElementException&)
189 return false;
192 rInfo.ServiceName = aValue;
194 // Obtain URL Template.
196 if ( !( rxHierNameAccess->getByHierarchicalName(
197 OUString::Concat(rProvider) + "/URLTemplate" ) >>= aValue ) )
199 OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
200 "Error getting item value!" );
203 rInfo.URLTemplate = aValue;
205 // Obtain Arguments.
207 if ( !( rxHierNameAccess->getByHierarchicalName(
208 OUString::Concat(rProvider) + "/Arguments" ) >>= aValue ) )
210 OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
211 "Error getting item value!" );
214 rInfo.Arguments = aValue;
215 return true;
221 // UniversalContentBroker Implementation.
224 UniversalContentBroker::UniversalContentBroker(
225 const Reference< css::uno::XComponentContext >& xContext )
226 : m_xContext( xContext ),
227 m_nCommandId( 0 )
229 OSL_ENSURE( m_xContext.is(),
230 "UniversalContentBroker ctor: No service manager" );
234 // virtual
235 UniversalContentBroker::~UniversalContentBroker()
240 // XComponent methods.
243 // virtual
244 void SAL_CALL UniversalContentBroker::dispose()
246 if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
248 EventObject aEvt;
249 aEvt.Source = static_cast< XComponent* >(this);
250 m_pDisposeEventListeners->disposeAndClear( aEvt );
253 if ( m_xNotifier.is() )
254 m_xNotifier->removeChangesListener( this );
258 // virtual
259 void SAL_CALL UniversalContentBroker::addEventListener(
260 const Reference< XEventListener >& Listener )
262 if ( !m_pDisposeEventListeners )
263 m_pDisposeEventListeners.reset( new OInterfaceContainerHelper3<css::lang::XEventListener>( m_aMutex ) );
265 m_pDisposeEventListeners->addInterface( Listener );
269 // virtual
270 void SAL_CALL UniversalContentBroker::removeEventListener(
271 const Reference< XEventListener >& Listener )
273 if ( m_pDisposeEventListeners )
274 m_pDisposeEventListeners->removeInterface( Listener );
276 // Note: Don't want to delete empty container here -> performance.
280 // XServiceInfo methods.
282 OUString SAL_CALL UniversalContentBroker::getImplementationName()
284 return u"com.sun.star.comp.ucb.UniversalContentBroker"_ustr;
286 sal_Bool SAL_CALL UniversalContentBroker::supportsService( const OUString& ServiceName )
288 return cppu::supportsService( this, ServiceName );
290 css::uno::Sequence< OUString > SAL_CALL UniversalContentBroker::getSupportedServiceNames()
292 return { u"com.sun.star.ucb.UniversalContentBroker"_ustr };
296 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
297 ucb_UniversalContentBroker_get_implementation(
298 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
300 return cppu::acquire(new UniversalContentBroker(context));
304 // XInitialization methods.
307 // virtual
308 void SAL_CALL UniversalContentBroker::initialize( const css::uno::Sequence< Any >& aArguments )
311 osl::MutexGuard aGuard(m_aMutex);
312 if (m_aArguments.hasElements())
314 if (aArguments.hasElements()
315 && !(m_aArguments.getLength() == 2
316 && aArguments.getLength() == 2
317 && m_aArguments[0] == aArguments[0]
318 && m_aArguments[1] == aArguments[1]))
320 throw IllegalArgumentException(
321 u"UCB reinitialized with different arguments"_ustr,
322 getXWeak(), 0);
324 return;
326 if (!aArguments.hasElements())
328 m_aArguments = { Any(u"Local"_ustr), Any(u"Office"_ustr) };
330 else
332 m_aArguments = aArguments;
335 configureUcb();
339 // XContentProviderManager methods.
342 // virtual
343 Reference< XContentProvider > SAL_CALL
344 UniversalContentBroker::registerContentProvider(
345 const Reference< XContentProvider >& Provider,
346 const OUString& Scheme,
347 sal_Bool ReplaceExisting )
349 osl::MutexGuard aGuard(m_aMutex);
351 ProviderMap_Impl::iterator aIt;
354 aIt = m_aProviders.find(Scheme);
356 catch (const IllegalArgumentException&)
358 return nullptr; //@@@
361 Reference< XContentProvider > xPrevious;
362 if (aIt == m_aProviders.end())
364 ProviderList_Impl aList;
365 aList.push_front( ProviderListEntry_Impl(Provider) );
368 m_aProviders.add(Scheme, aList);
370 catch (const IllegalArgumentException&)
372 return nullptr; //@@@
375 else
377 if (!ReplaceExisting)
378 throw DuplicateProviderException();
380 ProviderList_Impl & rList = aIt->getValue();
381 xPrevious = rList.front().getProvider();
382 rList.push_front( ProviderListEntry_Impl(Provider) );
385 return xPrevious;
389 // virtual
390 void SAL_CALL UniversalContentBroker::deregisterContentProvider(
391 const Reference< XContentProvider >& Provider,
392 const OUString& Scheme )
394 osl::MutexGuard aGuard(m_aMutex);
396 ProviderMap_Impl::iterator aMapIt;
399 aMapIt = m_aProviders.find(Scheme);
401 catch (const IllegalArgumentException&)
403 return; //@@@
406 if (aMapIt != m_aProviders.end())
408 ProviderList_Impl & rList = aMapIt->getValue();
410 auto aListIt = std::find_if(rList.begin(), rList.end(),
411 [&Provider](const ProviderListEntry_Impl& rEntry) { return rEntry.getProvider() == Provider; });
412 if (aListIt != rList.end())
413 rList.erase(aListIt);
415 if (rList.empty())
416 m_aProviders.erase(aMapIt);
421 // virtual
422 css::uno::Sequence< ContentProviderInfo > SAL_CALL
423 UniversalContentBroker::queryContentProviders()
425 // Return a list with information about active(!) content providers.
427 osl::MutexGuard aGuard(m_aMutex);
429 css::uno::Sequence< ContentProviderInfo > aSeq( m_aProviders.size() );
430 ContentProviderInfo* pInfo = aSeq.getArray();
432 ProviderMap_Impl::const_iterator end = m_aProviders.end();
433 for (ProviderMap_Impl::const_iterator it(m_aProviders.begin()); it != end;
434 ++it)
436 // Note: Active provider is always the first list element.
437 pInfo->ContentProvider = it->getValue().front().getProvider();
438 pInfo->Scheme = it->getRegexp();
439 ++pInfo;
442 return aSeq;
446 // virtual
447 Reference< XContentProvider > SAL_CALL
448 UniversalContentBroker::queryContentProvider( const OUString&
449 Identifier )
451 return queryContentProvider( Identifier, false );
455 // XContentProvider methods.
458 // virtual
459 Reference< XContent > SAL_CALL UniversalContentBroker::queryContent(
460 const Reference< XContentIdentifier >& Identifier )
463 // Let the content provider for the scheme given with the content
464 // identifier create the XContent instance.
467 if ( !Identifier.is() )
468 return Reference< XContent >();
470 Reference< XContentProvider > xProv =
471 queryContentProvider( Identifier->getContentIdentifier(), true );
472 if ( xProv.is() )
473 return xProv->queryContent( Identifier );
475 return Reference< XContent >();
479 // virtual
480 sal_Int32 SAL_CALL UniversalContentBroker::compareContentIds(
481 const Reference< XContentIdentifier >& Id1,
482 const Reference< XContentIdentifier >& Id2 )
484 OUString aURI1( Id1->getContentIdentifier() );
485 OUString aURI2( Id2->getContentIdentifier() );
487 Reference< XContentProvider > xProv1
488 = queryContentProvider( aURI1, true );
489 Reference< XContentProvider > xProv2
490 = queryContentProvider( aURI2, true );
492 // When both identifiers belong to the same provider, let that provider
493 // compare them; otherwise, simply compare the URI strings (which must
494 // be different):
495 if ( xProv1.is() && ( xProv1 == xProv2 ) )
496 return xProv1->compareContentIds( Id1, Id2 );
497 else
498 return aURI1.compareTo( aURI2 );
502 // XContentIdentifierFactory methods.
505 // virtual
506 Reference< XContentIdentifier > SAL_CALL
507 UniversalContentBroker::createContentIdentifier(
508 const OUString& ContentId )
511 // Let the content provider for the scheme given with content
512 // identifier create the XContentIdentifier instance, if he supports
513 // the XContentIdentifierFactory interface. Otherwise create standard
514 // implementation object for XContentIdentifier.
517 Reference< XContentIdentifier > xIdentifier;
519 Reference< XContentProvider > xProv
520 = queryContentProvider( ContentId, true );
521 if ( xProv.is() )
523 Reference< XContentIdentifierFactory > xFac( xProv, UNO_QUERY );
524 if ( xFac.is() )
525 xIdentifier = xFac->createContentIdentifier( ContentId );
528 if ( !xIdentifier.is() )
529 xIdentifier = new ContentIdentifier( ContentId );
531 return xIdentifier;
535 // XCommandProcessor methods.
538 // virtual
539 sal_Int32 SAL_CALL UniversalContentBroker::createCommandIdentifier()
541 osl::MutexGuard aGuard( m_aMutex );
543 // Just increase counter on every call to generate an identifier.
544 return ++m_nCommandId;
548 // virtual
549 Any SAL_CALL UniversalContentBroker::execute(
550 const Command& aCommand,
551 sal_Int32,
552 const Reference< XCommandEnvironment >& Environment )
554 Any aRet;
557 // Note: Don't forget to adapt ucb_commands::CommandProcessorInfo
558 // ctor in ucbcmds.cxx when adding new commands!
561 if ( ( aCommand.Handle == GETCOMMANDINFO_HANDLE ) || aCommand.Name == GETCOMMANDINFO_NAME )
564 // getCommandInfo
567 aRet <<= getCommandInfo();
569 else if ( ( aCommand.Handle == GLOBALTRANSFER_HANDLE ) || aCommand.Name == GLOBALTRANSFER_NAME )
572 // globalTransfer
575 GlobalTransferCommandArgument2 aTransferArg;
576 if ( !( aCommand.Argument >>= aTransferArg ) )
578 GlobalTransferCommandArgument aArg;
579 if ( !( aCommand.Argument >>= aArg ) )
581 ucbhelper::cancelCommandExecution(
582 Any( IllegalArgumentException(
583 u"Wrong argument type!"_ustr,
584 getXWeak(),
585 -1 ) ),
586 Environment );
587 // Unreachable
590 // Copy infos into the new structure
591 aTransferArg.Operation = aArg.Operation;
592 aTransferArg.SourceURL = aArg.SourceURL;
593 aTransferArg.TargetURL = aArg.TargetURL;
594 aTransferArg.NewTitle = aArg.NewTitle;
595 aTransferArg.NameClash = aArg.NameClash;
598 globalTransfer( aTransferArg, Environment );
600 else if ( ( aCommand.Handle == CHECKIN_HANDLE ) || aCommand.Name == CHECKIN_NAME )
602 ucb::CheckinArgument aCheckinArg;
603 if ( !( aCommand.Argument >>= aCheckinArg ) )
605 ucbhelper::cancelCommandExecution(
606 Any( IllegalArgumentException(
607 u"Wrong argument type!"_ustr,
608 getXWeak(),
609 -1 ) ),
610 Environment );
611 // Unreachable
613 aRet = checkIn( aCheckinArg, Environment );
615 else
618 // Unknown command
621 ucbhelper::cancelCommandExecution(
622 Any( UnsupportedCommandException(
623 OUString(),
624 getXWeak() ) ),
625 Environment );
626 // Unreachable
629 return aRet;
633 // XCommandProcessor2 methods.
636 // virtual
637 void SAL_CALL UniversalContentBroker::releaseCommandIdentifier(sal_Int32 /*aCommandId*/)
639 // @@@ Not implemented ( yet).
643 // virtual
644 void SAL_CALL UniversalContentBroker::abort( sal_Int32 )
646 // @@@ Not implemented ( yet).
650 // XChangesListener methods
653 // virtual
654 void SAL_CALL UniversalContentBroker::changesOccurred( const util::ChangesEvent& Event )
656 if ( !Event.Changes.hasElements() )
657 return;
659 uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess;
660 Event.Base >>= xHierNameAccess;
662 OSL_ASSERT( xHierNameAccess.is() );
664 ContentProviderDataList aData;
665 for ( const util::ElementChange& rElem : Event.Changes )
667 OUString aKey;
668 rElem.Accessor >>= aKey;
670 ContentProviderData aInfo;
672 // Removal of UCPs from the configuration leads to changesOccurred
673 // notifications, too, but it is hard to tell for a given
674 // ElementChange whether it is an addition or a removal, so as a
675 // heuristic consider as removals those that cause a
676 // NoSuchElementException in createContentProviderData.
678 // For now, removal of UCPs from the configuration is simply ignored
679 // (and not reflected in the UCB's data structures):
680 if (createContentProviderData(aKey, xHierNameAccess, aInfo))
682 aData.push_back(aInfo);
686 prepareAndRegister(aData);
690 // XEventListener methods
693 // virtual
694 void SAL_CALL UniversalContentBroker::disposing(const lang::EventObject&)
696 if ( m_xNotifier.is() )
698 osl::Guard< osl::Mutex > aGuard( m_aMutex );
700 if ( m_xNotifier.is() )
701 m_xNotifier.clear();
706 // Non-interface methods
709 Reference< XContentProvider > UniversalContentBroker::queryContentProvider(
710 const OUString& Identifier,
711 bool bResolved )
713 osl::MutexGuard aGuard( m_aMutex );
715 ProviderList_Impl const * pList = m_aProviders.map( Identifier );
716 return pList ? bResolved ? pList->front().getResolvedProvider()
717 : pList->front().getProvider()
718 : Reference< XContentProvider >();
721 void UniversalContentBroker::configureUcb()
723 OUString aKey1;
724 OUString aKey2;
725 if (m_aArguments.getLength() < 2
726 || !(m_aArguments[0] >>= aKey1) || !(m_aArguments[1] >>= aKey2))
728 OSL_FAIL("UniversalContentBroker::configureUcb(): Bad arguments");
729 return;
732 ContentProviderDataList aData;
733 if (!getContentProviderData(aKey1, aKey2, aData))
735 SAL_WARN( "ucb", "No configuration");
736 return;
739 prepareAndRegister(aData);
742 void UniversalContentBroker::prepareAndRegister(
743 const ContentProviderDataList& rData)
745 for (const auto& rContentProviderData : rData)
747 OUString aProviderArguments;
748 if (fillPlaceholders(rContentProviderData.Arguments,
749 m_aArguments,
750 &aProviderArguments))
752 registerAtUcb(this,
753 m_xContext,
754 rContentProviderData.ServiceName,
755 aProviderArguments,
756 rContentProviderData.URLTemplate);
759 else
760 OSL_FAIL("UniversalContentBroker::prepareAndRegister(): Bad argument placeholders");
765 bool UniversalContentBroker::getContentProviderData(
766 std::u16string_view rKey1,
767 std::u16string_view rKey2,
768 ContentProviderDataList & rListToFill )
770 if ( !m_xContext.is() || rKey1.empty() || rKey2.empty() )
772 OSL_FAIL( "UniversalContentBroker::getContentProviderData - Invalid argument!" );
773 return false;
778 uno::Reference< lang::XMultiServiceFactory > xConfigProv =
779 configuration::theDefaultProvider::get( m_xContext );
781 OUStringBuffer aFullPath(128);
782 aFullPath.append(
783 "/org.openoffice.ucb.Configuration/ContentProviders"
784 "/['" );
785 makeAndAppendXMLName( aFullPath, rKey1 );
786 aFullPath.append( "']/SecondaryKeys/['" );
787 makeAndAppendXMLName( aFullPath, rKey2 );
788 aFullPath.append( "']/ProviderData" );
790 uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
792 {"nodepath", uno::Any(aFullPath.makeStringAndClear())}
793 }));
795 uno::Reference< uno::XInterface > xInterface(
796 xConfigProv->createInstanceWithArguments(
797 u"com.sun.star.configuration.ConfigurationAccess"_ustr,
798 aArguments ) );
800 if ( !m_xNotifier.is() )
802 m_xNotifier.set( xInterface, uno::UNO_QUERY_THROW );
804 m_xNotifier->addChangesListener( this );
807 uno::Reference< container::XNameAccess > xNameAccess(
808 xInterface, uno::UNO_QUERY_THROW );
810 const uno::Sequence< OUString > aElems = xNameAccess->getElementNames();
812 if ( aElems.hasElements() )
814 uno::Reference< container::XHierarchicalNameAccess >
815 xHierNameAccess( xInterface, uno::UNO_QUERY_THROW );
817 // Iterate over children.
818 for ( const auto& rElem : aElems )
824 ContentProviderData aInfo;
826 OUStringBuffer aElemBuffer( "['" );
827 makeAndAppendXMLName( aElemBuffer, rElem );
828 aElemBuffer.append( "']" );
830 OSL_VERIFY(
831 createContentProviderData(
832 aElemBuffer, xHierNameAccess,
833 aInfo));
835 rListToFill.push_back( aInfo );
837 catch (const container::NoSuchElementException&)
839 // getByHierarchicalName
840 OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
841 "caught NoSuchElementException!" );
846 catch (const uno::RuntimeException&)
848 TOOLS_WARN_EXCEPTION( "ucb", "" );
849 return false;
851 catch (const uno::Exception&)
853 // createInstance, createInstanceWithArguments
855 TOOLS_WARN_EXCEPTION( "ucb", "" );
856 return false;
859 return true;
863 // ProviderListEntry_Impl implementation.
866 Reference< XContentProvider > const & ProviderListEntry_Impl::resolveProvider() const
868 if ( !m_xResolvedProvider.is() )
870 Reference< XContentProviderSupplier > xSupplier(
871 m_xProvider, UNO_QUERY );
872 if ( xSupplier.is() )
873 m_xResolvedProvider = xSupplier->getContentProvider();
875 if ( !m_xResolvedProvider.is() )
876 m_xResolvedProvider = m_xProvider;
879 return m_xResolvedProvider;
882 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */