Resolves: tdf#126928 allow link updates in an intermediate linked document

... if link updates are allowed in the current document and that
intermediate document resides in a trusted location.

This works with both, the "Always (from trusted locations)" and
the "On request" settings under Tools -> Options -> Calc ->
General. It can't work with documents residing in a non-trusted
location as there is no way to allow updates on demand for a such
loaded document (hidden via formulas).

Change-Id: Ie483f7743db7c6d5cf947dc16a9c3660855f3423
Reviewed-on: https://gerrit.libreoffice.org/77588
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
(cherry picked from commit 54bf84746a2a9a2e2aaf0df9e429b0cfd538f640)
Reviewed-on: https://gerrit.libreoffice.org/77604
Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index 372686d..024a3470 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -584,15 +584,22 @@ bool ScDocShell::Load( SfxMedium& rMedium )
    bool bRet = SfxObjectShell::Load(rMedium);
    if (bRet)
    {
        comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
        rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);

        if (GetMedium())
        {
            const SfxUInt16Item* pUpdateDocItem = SfxItemSet::GetItem<SfxUInt16Item>(rMedium.GetItemSet(), SID_UPDATEDOCMODE, false);
            m_nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : css::document::UpdateDocMode::NO_UPDATE;
        }

        // GetLinkUpdateModeState() evaluates m_nCanUpdate so that must have
        // been set first. Do not override an already forbidden LinkUpdate (the
        // default is allow).
        comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
        if (rEmbeddedObjectContainer.getUserAllowsLinkUpdate())
        {
            // For anything else than LM_ALWAYS we need user confirmation.
            rEmbeddedObjectContainer.setUserAllowsLinkUpdate( GetLinkUpdateModeState() == LM_ALWAYS);
        }

        {
            //  prepare a valid document for XML filter
            //  (for ConvertFrom, InitNew is called before)
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
index 8d220ec..19a49af 100644
--- a/sc/source/ui/docshell/docsh4.cxx
+++ b/sc/source/ui/docshell/docsh4.cxx
@@ -144,6 +144,41 @@ IMPL_LINK_NOARG( ScDocShell, ReloadAllLinksHdl, Button*, void )
    SAL_WARN_IF(!pViewFrame, "sc", "expected there to be a ViewFrame");
}

ScLkUpdMode ScDocShell::GetLinkUpdateModeState() const
{
    const ScDocument& rDoc = GetDocument();

    ScLkUpdMode nSet = rDoc.GetLinkMode();

    if (nSet == LM_UNKNOWN)
    {
        ScAppOptions aAppOptions = SC_MOD()->GetAppOptions();
        nSet = aAppOptions.GetLinkMode();
    }

    if (m_nCanUpdate == css::document::UpdateDocMode::NO_UPDATE)
        nSet = LM_NEVER;
    else if (m_nCanUpdate == css::document::UpdateDocMode::FULL_UPDATE)
        nSet = LM_ALWAYS;

    if (nSet == LM_ALWAYS
            && !(SvtSecurityOptions().isTrustedLocationUriForUpdatingLinks(
                    GetMedium() == nullptr ? OUString() : GetMedium()->GetName())
                || (IsDocShared()
                    && SvtSecurityOptions().isTrustedLocationUriForUpdatingLinks(
                        GetSharedFileURL()))))
    {
        nSet = LM_ON_DEMAND;
    }
    if (m_nCanUpdate == css::document::UpdateDocMode::QUIET_UPDATE
            && nSet == LM_ON_DEMAND)
    {
        nSet = LM_NEVER;
    }

    return nSet;
}

void ScDocShell::Execute( SfxRequest& rReq )
{
    const SfxItemSet* pReqArgs = rReq.GetArgs();
@@ -441,37 +476,7 @@ void ScDocShell::Execute( SfxRequest& rReq )
            break;
        case SID_UPDATETABLINKS:
            {
                ScDocument& rDoc = GetDocument();

                ScLkUpdMode nSet = rDoc.GetLinkMode();

                if(nSet==LM_UNKNOWN)
                {
                    ScAppOptions aAppOptions=SC_MOD()->GetAppOptions();
                    nSet=aAppOptions.GetLinkMode();
                }

                if (m_nCanUpdate == css::document::UpdateDocMode::NO_UPDATE)
                    nSet = LM_NEVER;
                else if (m_nCanUpdate == css::document::UpdateDocMode::FULL_UPDATE)
                    nSet = LM_ALWAYS;

                if (nSet == LM_ALWAYS
                    && !(SvtSecurityOptions()
                         .isTrustedLocationUriForUpdatingLinks(
                             GetMedium() == nullptr
                             ? OUString() : GetMedium()->GetName())
                         || (IsDocShared()
                             && SvtSecurityOptions().isTrustedLocationUriForUpdatingLinks(
                                 GetSharedFileURL()))))
                {
                    nSet = LM_ON_DEMAND;
                }
                if (m_nCanUpdate == css::document::UpdateDocMode::QUIET_UPDATE
                    && nSet == LM_ON_DEMAND)
                {
                    nSet = LM_NEVER;
                }
                ScLkUpdMode nSet = GetLinkUpdateModeState();

                if (nSet == LM_ALWAYS)
                {
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 61ea86d..7c23d63 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -58,6 +58,7 @@
#include <columnspanset.hxx>
#include <column.hxx>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/document/UpdateDocMode.hpp>
#include <sal/log.hxx>

#include <memory>
@@ -2484,6 +2485,11 @@ SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, OUSt

    // If the current document is allowed to execute macros then the referenced
    // document may execute macros according to the security configuration.
    // Similar for UpdateDocMode to update links, just that if we reach here
    // the user already allowed updates and intermediate documents are expected
    // to update as well. When loading the document ScDocShell::Load() will
    // check through ScDocShell::GetLinkUpdateModeState() if its location is
    // trusted.
    SfxObjectShell* pShell = mpDoc->GetDocumentShell();
    if (pShell)
    {
@@ -2495,6 +2501,8 @@ SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, OUSt
                    static_cast<const SfxUInt16Item*>(pItem)->GetValue() != css::document::MacroExecMode::NEVER_EXECUTE)
                pSet->Put( SfxUInt16Item( SID_MACROEXECMODE, css::document::MacroExecMode::USE_CONFIG));
        }

        pSet->Put( SfxUInt16Item( SID_UPDATEDOCMODE, css::document::UpdateDocMode::FULL_UPDATE));
    }

    unique_ptr<SfxMedium> pMedium(new SfxMedium(aFile, StreamMode::STD_READ, pFilter, std::move(pSet)));
diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx
index 1a339d3..d39e316 100644
--- a/sc/source/ui/inc/docsh.hxx
+++ b/sc/source/ui/inc/docsh.hxx
@@ -217,6 +217,7 @@ public:

    void    GetDocStat( ScDocStat& rDocStat );

    const ScDocument& GetDocument() const { return m_aDocument; }
    ScDocument&     GetDocument()   { return m_aDocument; }
    ScDocFunc&      GetDocFunc()    { return *m_pDocFunc; }

@@ -299,6 +300,7 @@ public:
    void            UpdateLinks() override;
    void            ReloadAllLinks();
    void            ReloadTabLinks();
    ScLkUpdMode     GetLinkUpdateModeState() const;

    void            SetFormulaOptions( const ScFormulaOptions& rOpt, bool bForLoading = false );
    /**