bdede2a
From a3f5d838d091df6c1582b0fb6d539292edf536a0 Mon Sep 17 00:00:00 2001
bdede2a
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
bdede2a
Date: Wed, 10 Jan 2018 14:27:35 +0000
bdede2a
Subject: [PATCH] limit WEBSERVICE to http[s] protocols
bdede2a
MIME-Version: 1.0
bdede2a
Content-Type: text/plain; charset=UTF-8
bdede2a
Content-Transfer-Encoding: 8bit
bdede2a
bdede2a
and like excel...
bdede2a
bdede2a
'For protocols that aren’t supported, such as ftp:// or file://, WEBSERVICE
bdede2a
returns the #VALUE! error value.'
bdede2a
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/47776
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
bdede2a
bdede2a
Better handle ScDde formulas with missing dde-link entries
bdede2a
bdede2a
typically each ScDde formula has a matching table:dde-link which
bdede2a
results in a ScDdeLink getting inserted during the load. If that dde-link
bdede2a
is missing then no ScDdeLink exists and ScDde() will create a new one without
bdede2a
cached content. So detect that ScDde is used in the freshing loaded ods
bdede2a
and defer fetching new content until the right time.
bdede2a
bdede2a
only call GetHasMacroFunc to set SetHasMacroFunc
bdede2a
bdede2a
and bHasMacroFunc is not accessed any other way, so this is an oxbow
bdede2a
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/47757
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
Tested-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
(cherry picked from commit b0597ba5d745974fce752e1b677451a19350d351)
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/47818
bdede2a
Reviewed-by: Eike Rathke <erack@redhat.com>
bdede2a
bdede2a
handle ocWebservice similarly to ocDde
bdede2a
bdede2a
might have too much in here seeing as we don't need to worry about
bdede2a
ocWebservice calling into itself
bdede2a
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/47819
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Eike Rathke <erack@redhat.com>
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xls and .xlsx formula cells
bdede2a
bdede2a
 This is a combination of 3 commits.
bdede2a
bdede2a
Move implementation to CheckLinkFormulaNeedingCheck() for further reuse
bdede2a
bdede2a
(cherry picked from commit 55e484c7bcd3ef218e08d3fd93f97bf98fd8cb7f)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xlsx cell formulas
bdede2a
bdede2a
(cherry picked from commit f96dbc3dd9c33202f75e29ef49d962386595995d)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xls cell formulas
bdede2a
bdede2a
(cherry picked from commit 6bc48275558c3f76c4da25eb8af3c48583ac5599)
bdede2a
bdede2a
a6dd195f7eb4d43483e87eeca59f651e7bf2dcb8
bdede2a
2587fbc4fec39b6f2c8e733331815a2953dee308
bdede2a
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/48143
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
Tested-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for conditional format expressions
bdede2a
bdede2a
 This is a combination of 4 commits.
bdede2a
bdede2a
Prepare CheckLinkFormulaNeedingCheck() to use either RPN or tokenized code
bdede2a
bdede2a
Conditional format formulas aren't finally compiled until needed
bdede2a
so the check will have to operate on the tokenized expression
bdede2a
instead of RPN code.
bdede2a
bdede2a
(cherry picked from commit faa0305ba3d0dc698fce4915d4f3a1fb52422380)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .ods conditional format expressions
bdede2a
bdede2a
(cherry picked from commit 2930ba2ac5d9423f2848b968edcd8ddc71966186)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xlsx conditional format expressions
bdede2a
bdede2a
(cherry picked from commit fef24d9f999ee54d7936900485d97ff26656f517)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xls conditional format expressions
bdede2a
bdede2a
(cherry picked from commit af2a2a0c72db312902e466c36697b5c198041e82)
bdede2a
bdede2a
45eb1ab5efa0ec9da2663f20427d2474ce300826
bdede2a
31ede1a23223a798141a0891deeabd8cf88fff58
bdede2a
afa112cc591b411d80ead48bf726788d361f6eb3
bdede2a
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/48719
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
Tested-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for named expressions
bdede2a
bdede2a
 This is a combination of 3 commits.
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .ods named expressions
bdede2a
bdede2a
This is specifically necessary for named expressions that are used
bdede2a
in conditional format formulas, for which RPN is generated at a
bdede2a
later stage, not during import.
bdede2a
bdede2a
(cherry picked from commit eae9648e99be53ba441d9d8207aac6f3ce211ef2)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xls named expressions
bdede2a
bdede2a
(cherry picked from commit 8512f13c42ae3fbb287a555616fe10ff04295616)
bdede2a
bdede2a
CheckLinkFormulaNeedingCheck() for .xlsx named expressions
bdede2a
bdede2a
(cherry picked from commit a1f933ee2b9e23a505d937035821e9571cf4119c)
bdede2a
bdede2a
 Conflicts:
bdede2a
	sc/source/filter/oox/defnamesbuffer.cxx
bdede2a
bdede2a
e03cb5767c34f8157a492a6d6c3b0700d065052d
bdede2a
217c89822ab477a6c383d170ae739e44efd10fa3
bdede2a
bdede2a
Change-Id: I0e9c6fd3426fad56a199eafac48de9b0f23914b3
bdede2a
016b53288076d83dd49e92e245346a5f7f560522
bdede2a
0145f38cc1c1f9ff514a496f7101d81cde9e7c67
bdede2a
541d2b6e12a88371c064b901b00e71206ee0c18e
bdede2a
68837e9bd33f125ab47b10b1a6fa18175abd1627
bdede2a
54ab8dc14f81d6b18b0d17f448187d19d8e396fc
bdede2a
Reviewed-on: https://gerrit.libreoffice.org/48858
bdede2a
Tested-by: Jenkins <ci@libreoffice.org>
bdede2a
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
Tested-by: Caolán McNamara <caolanm@redhat.com>
bdede2a
---
bdede2a
 sc/Library_sc.mk                          |   1 +
bdede2a
 sc/inc/document.hxx                       |   8 ++-
bdede2a
 sc/inc/documentlinkmgr.hxx                |   6 +-
bdede2a
 sc/qa/unit/ucalc.cxx                      |   2 +-
bdede2a
 sc/source/core/data/conditio.cxx          |   6 ++
bdede2a
 sc/source/core/data/documen2.cxx          |   2 +-
bdede2a
 sc/source/core/data/documen8.cxx          |  23 +++++++
bdede2a
 sc/source/core/data/formulacell.cxx       |   7 +-
bdede2a
 sc/source/core/inc/webservicelink.hxx     |  49 ++++++++++++++
bdede2a
 sc/source/core/tool/interpr2.cxx          |   8 ++-
bdede2a
 sc/source/core/tool/interpr7.cxx          | 106 ++++++++++++++++++++++--------
bdede2a
 sc/source/core/tool/rangenam.cxx          |   8 ++-
bdede2a
 sc/source/core/tool/webservicelink.cxx    | 106 ++++++++++++++++++++++++++++++
bdede2a
 sc/source/filter/excel/excform.cxx        |   1 +
bdede2a
 sc/source/filter/excel/excform8.cxx       |   1 +
bdede2a
 sc/source/filter/excel/impop.cxx          |   1 +
bdede2a
 sc/source/filter/excel/xicontent.cxx      |   6 ++
bdede2a
 sc/source/filter/excel/xiname.cxx         |   3 +
bdede2a
 sc/source/filter/oox/condformatbuffer.cxx |   2 +
bdede2a
 sc/source/filter/oox/defnamesbuffer.cxx   |   2 +
bdede2a
 sc/source/filter/oox/formulabuffer.cxx    |   4 ++
bdede2a
 sc/source/ui/docshell/docsh4.cxx          |   4 +-
bdede2a
 sc/source/ui/docshell/documentlinkmgr.cxx |  20 ++++--
bdede2a
 sc/source/ui/view/tabvwsh4.cxx            |   2 +-
bdede2a
 24 files changed, 329 insertions(+), 49 deletions(-)
bdede2a
 create mode 100644 sc/source/core/inc/webservicelink.hxx
bdede2a
 create mode 100644 sc/source/core/tool/webservicelink.cxx
bdede2a
bdede2a
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
bdede2a
index 3714c966a62e..05a3ee49a32c 100644
bdede2a
--- a/sc/Library_sc.mk
bdede2a
+++ b/sc/Library_sc.mk
bdede2a
@@ -285,6 +285,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
bdede2a
     sc/source/core/tool/unitconv \
bdede2a
     sc/source/core/tool/userlist \
bdede2a
     sc/source/core/tool/viewopti \
bdede2a
+    sc/source/core/tool/webservicelink \
bdede2a
     sc/source/core/tool/zforauto \
bdede2a
     sc/source/filter/xml/datastreamimport \
bdede2a
     sc/source/filter/xml/XMLCalculationSettingsContext \
bdede2a
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
bdede2a
index f5f9f0387174..d25ca0b913a8 100644
bdede2a
--- a/sc/inc/document.hxx
bdede2a
+++ b/sc/inc/document.hxx
bdede2a
@@ -448,7 +448,7 @@ private:
bdede2a
     // for detective update, is set for each change of a formula
bdede2a
     bool                bDetectiveDirty;
bdede2a
 
bdede2a
-    bool                bHasMacroFunc;      // valid only after loading
bdede2a
+    bool                bLinkFormulaNeedingCheck; // valid only after loading, for ocDde and ocWebservice
bdede2a
 
bdede2a
     sal_uInt8               nAsianCompression;
bdede2a
     sal_uInt8               nAsianKerning;
bdede2a
@@ -1928,8 +1928,10 @@ public:
bdede2a
     bool            IsDetectiveDirty() const     { return bDetectiveDirty; }
bdede2a
     void            SetDetectiveDirty(bool bSet) { bDetectiveDirty = bSet; }
bdede2a
 
bdede2a
-    bool            GetHasMacroFunc() const      { return bHasMacroFunc; }
bdede2a
-    void            SetHasMacroFunc(bool bSet)   { bHasMacroFunc = bSet; }
bdede2a
+    bool            HasLinkFormulaNeedingCheck() const      { return bLinkFormulaNeedingCheck; }
bdede2a
+    void            SetLinkFormulaNeedingCheck(bool bSet)   { bLinkFormulaNeedingCheck = bSet; }
bdede2a
+    /** Check token array and set link check if ocDde/ocWebservice is contained. */
bdede2a
+    SC_DLLPUBLIC void CheckLinkFormulaNeedingCheck( const ScTokenArray& rCode );
bdede2a
 
bdede2a
     void            SetRangeOverflowType(sal_uInt32 nType)  { nRangeOverflowType = nType; }
bdede2a
     bool            HasRangeOverflow() const                { return nRangeOverflowType != 0; }
bdede2a
diff --git a/sc/inc/documentlinkmgr.hxx b/sc/inc/documentlinkmgr.hxx
bdede2a
index d5d801a4aeb2..86dba66f2d3d 100644
bdede2a
--- a/sc/inc/documentlinkmgr.hxx
bdede2a
+++ b/sc/inc/documentlinkmgr.hxx
bdede2a
@@ -55,9 +55,9 @@ public:
bdede2a
     bool idleCheckLinks();
bdede2a
 
bdede2a
     bool hasDdeLinks() const;
bdede2a
-    bool hasDdeOrOleLinks() const;
bdede2a
+    bool hasDdeOrOleOrWebServiceLinks() const;
bdede2a
 
bdede2a
-    bool updateDdeOrOleLinks(vcl::Window* pWin);
bdede2a
+    bool updateDdeOrOleOrWebServiceLinks(vcl::Window* pWin);
bdede2a
 
bdede2a
     void updateDdeLink( const OUString& rAppl, const OUString& rTopic, const OUString& rItem );
bdede2a
 
bdede2a
@@ -65,7 +65,7 @@ public:
bdede2a
 
bdede2a
     void disconnectDdeLinks();
bdede2a
 private:
bdede2a
-    bool hasDdeOrOleLinks(bool bDde, bool bOle) const;
bdede2a
+    bool hasDdeOrOleOrWebServiceLinks(bool bDde, bool bOle, bool bWebService) const;
bdede2a
 };
bdede2a
 
bdede2a
 }
bdede2a
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
bdede2a
index ea44ff7d4f3d..90ca51f47073 100644
bdede2a
--- a/sc/qa/unit/ucalc.cxx
bdede2a
+++ b/sc/qa/unit/ucalc.cxx
bdede2a
@@ -6215,7 +6215,7 @@ void Test::testEmptyCalcDocDefaults()
bdede2a
     CPPUNIT_ASSERT_EQUAL( false, m_pDoc->IdleCalcTextWidth() );
bdede2a
     CPPUNIT_ASSERT_EQUAL( true, m_pDoc->IsIdleEnabled() );
bdede2a
     CPPUNIT_ASSERT_EQUAL( false, m_pDoc->IsDetectiveDirty() );
bdede2a
-    CPPUNIT_ASSERT_EQUAL( false, m_pDoc->GetHasMacroFunc() );
bdede2a
+    CPPUNIT_ASSERT_EQUAL( false, m_pDoc->HasLinkFormulaNeedingCheck() );
bdede2a
     CPPUNIT_ASSERT_EQUAL( false, m_pDoc->IsChartListenerCollectionNeedsUpdate() );
bdede2a
 
bdede2a
     CPPUNIT_ASSERT_EQUAL( false, m_pDoc->HasRangeOverflow() );
bdede2a
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
bdede2a
index c970520f3377..1fc8ee34b60b 100644
bdede2a
--- a/sc/source/core/data/conditio.cxx
bdede2a
+++ b/sc/source/core/data/conditio.cxx
bdede2a
@@ -522,6 +522,12 @@ void ScConditionEntry::CompileXML()
bdede2a
     Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1),
bdede2a
              GetExpression(aSrcPos, 1, 0, eTempGrammar2),
bdede2a
              aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, true );
bdede2a
+
bdede2a
+    // Importing ocDde/ocWebservice?
bdede2a
+    if (pFormula1)
bdede2a
+        mpDoc->CheckLinkFormulaNeedingCheck(*pFormula1);
bdede2a
+    if (pFormula2)
bdede2a
+        mpDoc->CheckLinkFormulaNeedingCheck(*pFormula2);
bdede2a
 }
bdede2a
 
bdede2a
 void ScConditionEntry::SetSrcString( const OUString& rNew )
bdede2a
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
bdede2a
index 7a41f14c01c2..017f8629c910 100644
bdede2a
--- a/sc/source/core/data/documen2.cxx
bdede2a
+++ b/sc/source/core/data/documen2.cxx
bdede2a
@@ -200,7 +200,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
bdede2a
         bInDtorClear( false ),
bdede2a
         bExpandRefs( false ),
bdede2a
         bDetectiveDirty( false ),
bdede2a
-        bHasMacroFunc( false ),
bdede2a
+        bLinkFormulaNeedingCheck( false ),
bdede2a
         nAsianCompression(SC_ASIANCOMPRESSION_INVALID),
bdede2a
         nAsianKerning(SC_ASIANKERNING_INVALID),
bdede2a
         bPastingDrawFromOtherDoc( false ),
bdede2a
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
bdede2a
index 572d594b3697..49985b4cd93d 100644
bdede2a
--- a/sc/source/core/data/documen8.cxx
bdede2a
+++ b/sc/source/core/data/documen8.cxx
bdede2a
@@ -88,6 +88,7 @@
bdede2a
 #include "stringutil.hxx"
bdede2a
 #include <documentlinkmgr.hxx>
bdede2a
 #include <scopetools.hxx>
bdede2a
+#include <tokenarray.hxx>
bdede2a
 
bdede2a
 #include <memory>
bdede2a
 
bdede2a
@@ -1153,6 +1154,28 @@ void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode,
bdede2a
     }
bdede2a
 }
bdede2a
 
bdede2a
+void ScDocument::CheckLinkFormulaNeedingCheck( const ScTokenArray& rCode )
bdede2a
+{
bdede2a
+    if (HasLinkFormulaNeedingCheck())
bdede2a
+        return;
bdede2a
+
bdede2a
+    // Prefer RPN over tokenized formula if available.
bdede2a
+    if (rCode.GetCodeLen())
bdede2a
+    {
bdede2a
+        if (rCode.HasOpCodeRPN(ocDde) || rCode.HasOpCodeRPN(ocWebservice))
bdede2a
+            SetLinkFormulaNeedingCheck(true);
bdede2a
+    }
bdede2a
+    else if (rCode.GetLen())
bdede2a
+    {
bdede2a
+        if (rCode.HasOpCode(ocDde) || rCode.HasOpCode(ocWebservice))
bdede2a
+            SetLinkFormulaNeedingCheck(true);
bdede2a
+    }
bdede2a
+    else
bdede2a
+    {
bdede2a
+        assert(!"called with empty ScTokenArray");
bdede2a
+    }
bdede2a
+}
bdede2a
+
bdede2a
 // TimerDelays etc.
bdede2a
 void ScDocument::KeyInput( const KeyEvent& )
bdede2a
 {
bdede2a
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
bdede2a
index 381fb173d4b7..8eb4f9f23400 100644
bdede2a
--- a/sc/source/core/data/formulacell.cxx
bdede2a
+++ b/sc/source/core/data/formulacell.cxx
bdede2a
@@ -1379,10 +1379,9 @@ void ScFormulaCell::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rPr
bdede2a
             bChanged = true;
bdede2a
     }
bdede2a
 
bdede2a
-    //  Same as in Load: after loading, it must be known if ocMacro is in any formula
bdede2a
-    //  (for macro warning, CompileXML is called at the end of loading XML file)
bdede2a
-    if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
bdede2a
-        pDocument->SetHasMacroFunc( true );
bdede2a
+    //  After loading, it must be known if ocDde/ocWebservice is in any formula
bdede2a
+    //  (for external links warning, CompileXML is called at the end of loading XML file)
bdede2a
+    pDocument->CheckLinkFormulaNeedingCheck(*pCode);
bdede2a
 
bdede2a
     //volatile cells must be added here for import
bdede2a
     if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() ||
bdede2a
diff --git a/sc/source/core/inc/webservicelink.hxx b/sc/source/core/inc/webservicelink.hxx
bdede2a
new file mode 100644
bdede2a
index 000000000000..e61ebfdb4347
bdede2a
--- /dev/null
bdede2a
+++ b/sc/source/core/inc/webservicelink.hxx
bdede2a
@@ -0,0 +1,49 @@
bdede2a
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
bdede2a
+/*
bdede2a
+ * This file is part of the LibreOffice project.
bdede2a
+ *
bdede2a
+ * This Source Code Form is subject to the terms of the Mozilla Public
bdede2a
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
bdede2a
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
bdede2a
+ */
bdede2a
+
bdede2a
+#ifndef INCLUDED_SC_SOURCE_CORE_INC_WEBSERVICE_HXX
bdede2a
+#define INCLUDED_SC_SOURCE_CORE_INC_WEBSERVICE_HXX
bdede2a
+
bdede2a
+#include <address.hxx>
bdede2a
+#include <sfx2/lnkbase.hxx>
bdede2a
+#include <svl/broadcast.hxx>
bdede2a
+#include <types.hxx>
bdede2a
+
bdede2a
+class ScDocument;
bdede2a
+
bdede2a
+class ScWebServiceLink : public ::sfx2::SvBaseLink, public SvtBroadcaster
bdede2a
+{
bdede2a
+private:
bdede2a
+    ScDocument* pDoc;
bdede2a
+    OUString aURL; // connection/ link data
bdede2a
+    bool bHasResult; // is set aResult is useful
bdede2a
+    OUString aResult;
bdede2a
+
bdede2a
+public:
bdede2a
+    ScWebServiceLink(ScDocument* pD, const OUString& rURL);
bdede2a
+    virtual ~ScWebServiceLink() override;
bdede2a
+
bdede2a
+    // SvBaseLink override:
bdede2a
+    virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(const OUString& rMimeType,
bdede2a
+                                                         const css::uno::Any& rValue) override;
bdede2a
+
bdede2a
+    // SvtBroadcaster override:
bdede2a
+    virtual void ListenersGone() override;
bdede2a
+
bdede2a
+    // for interpreter:
bdede2a
+
bdede2a
+    const OUString& GetResult() const { return aResult; }
bdede2a
+    bool HasResult() const { return bHasResult; }
bdede2a
+
bdede2a
+    const OUString& GetURL() const { return aURL; }
bdede2a
+};
bdede2a
+
bdede2a
+#endif
bdede2a
+
bdede2a
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
bdede2a
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
bdede2a
index c40623320b3d..7f215495538b 100644
bdede2a
--- a/sc/source/core/tool/interpr2.cxx
bdede2a
+++ b/sc/source/core/tool/interpr2.cxx
bdede2a
@@ -2742,8 +2742,14 @@ void ScInterpreter::ScDde()
bdede2a
                     pBindings->Invalidate( SID_LINKS );             // Link-Manager enablen
bdede2a
             }
bdede2a
 
bdede2a
+            //if the document was just loaded, but the ScDdeLink entry was missing, then
bdede2a
+            //don't update this link until the links are updated in response to the users
bdede2a
+            //decision
bdede2a
+            if (!pDok->HasLinkFormulaNeedingCheck())
bdede2a
+            {
bdede2a
                                     //TODO: evaluate asynchron ???
bdede2a
-            pLink->TryUpdate();     //  TryUpdate doesn't call Update multiple times
bdede2a
+                pLink->TryUpdate(); //  TryUpdate doesn't call Update multiple times
bdede2a
+            }
bdede2a
 
bdede2a
             if (pMyFormulaCell)
bdede2a
             {
bdede2a
diff --git a/sc/source/core/tool/interpr7.cxx b/sc/source/core/tool/interpr7.cxx
bdede2a
index 48a34b3ece36..e2f562848a31 100644
bdede2a
--- a/sc/source/core/tool/interpr7.cxx
bdede2a
+++ b/sc/source/core/tool/interpr7.cxx
bdede2a
@@ -13,7 +13,9 @@
bdede2a
 #include "scmatrix.hxx"
bdede2a
 #include <rtl/strbuf.hxx>
bdede2a
 #include <formula/errorcodes.hxx>
bdede2a
+#include <sfx2/bindings.hxx>
bdede2a
 #include <svtools/miscopt.hxx>
bdede2a
+#include <tools/urlobj.hxx>
bdede2a
 
bdede2a
 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
bdede2a
 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
bdede2a
@@ -23,6 +25,10 @@
bdede2a
 #include <datastreamgettime.hxx>
bdede2a
 #include <dpobject.hxx>
bdede2a
 #include <document.hxx>
bdede2a
+#include <tokenarray.hxx>
bdede2a
+#include <webservicelink.hxx>
bdede2a
+
bdede2a
+#include <sc.hrc>
bdede2a
 
bdede2a
 #include <cstring>
bdede2a
 #include <memory>
bdede2a
@@ -234,6 +240,22 @@ void ScInterpreter::ScFilterXML()
bdede2a
     }
bdede2a
 }
bdede2a
 
bdede2a
+static ScWebServiceLink* lcl_GetWebServiceLink(const sfx2::LinkManager* pLinkMgr, const OUString& rURL)
bdede2a
+{
bdede2a
+    size_t nCount = pLinkMgr->GetLinks().size();
bdede2a
+    for (size_t i=0; i
bdede2a
+    {
bdede2a
+        ::sfx2::SvBaseLink* pBase = pLinkMgr->GetLinks()[i].get();
bdede2a
+        if (ScWebServiceLink* pLink = dynamic_cast<ScWebServiceLink*>(pBase))
bdede2a
+        {
bdede2a
+            if (pLink->GetURL() == rURL)
bdede2a
+                return pLink;
bdede2a
+        }
bdede2a
+    }
bdede2a
+
bdede2a
+    return nullptr;
bdede2a
+}
bdede2a
+
bdede2a
 void ScInterpreter::ScWebservice()
bdede2a
 {
bdede2a
     sal_uInt8 nParamCount = GetByte();
bdede2a
@@ -241,54 +263,82 @@ void ScInterpreter::ScWebservice()
bdede2a
     {
bdede2a
         OUString aURI = GetString().getString();
bdede2a
 
bdede2a
-        if(aURI.isEmpty())
bdede2a
+        if (aURI.isEmpty())
bdede2a
         {
bdede2a
             PushError( FormulaError::NoValue );
bdede2a
             return;
bdede2a
         }
bdede2a
 
bdede2a
-        uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
bdede2a
-        if(!xFileAccess.is())
bdede2a
+        INetURLObject aObj(aURI, INetProtocol::File);
bdede2a
+        INetProtocol eProtocol = aObj.GetProtocol();
bdede2a
+        if (eProtocol != INetProtocol::Http && eProtocol != INetProtocol::Https)
bdede2a
         {
bdede2a
-            PushError( FormulaError::NoValue );
bdede2a
+            PushError(FormulaError::NoValue);
bdede2a
             return;
bdede2a
         }
bdede2a
 
bdede2a
-        uno::Reference< io::XInputStream > xStream;
bdede2a
-        try {
bdede2a
-            xStream = xFileAccess->openFileRead( aURI );
bdede2a
-        }
bdede2a
-        catch (...)
bdede2a
+        if (!mpLinkManager)
bdede2a
         {
bdede2a
-            // don't let any exceptions pass
bdede2a
-            PushError( FormulaError::NoValue );
bdede2a
-            return;
bdede2a
-        }
bdede2a
-        if ( !xStream.is() )
bdede2a
-        {
bdede2a
-            PushError( FormulaError::NoValue );
bdede2a
+            PushError(FormulaError::NoValue);
bdede2a
             return;
bdede2a
         }
bdede2a
 
bdede2a
-        const sal_Int32 BUF_LEN = 8000;
bdede2a
-        uno::Sequence< sal_Int8 > buffer( BUF_LEN );
bdede2a
-        OStringBuffer aBuffer( 64000 );
bdede2a
+        // Need to reinterpret after loading (build links)
bdede2a
+        if (rArr.IsRecalcModeNormal())
bdede2a
+            rArr.SetExclusiveRecalcModeOnLoad();
bdede2a
+
bdede2a
+        //  while the link is not evaluated, idle must be disabled (to avoid circular references)
bdede2a
+        bool bOldEnabled = pDok->IsIdleEnabled();
bdede2a
+        pDok->EnableIdle(false);
bdede2a
+
bdede2a
+        // Get/ Create link object
bdede2a
+        ScWebServiceLink* pLink = lcl_GetWebServiceLink(mpLinkManager, aURI);
bdede2a
+
bdede2a
+        bool bWasError = (pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE);
bdede2a
 
bdede2a
-        sal_Int32 nRead = 0;
bdede2a
-        while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
bdede2a
+        if (!pLink)
bdede2a
         {
bdede2a
-            aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
bdede2a
-        }
bdede2a
+            pLink = new ScWebServiceLink(pDok, aURI);
bdede2a
+            mpLinkManager->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, aURI);
bdede2a
+            if ( mpLinkManager->GetLinks().size() == 1 )                    // the first one?
bdede2a
+            {
bdede2a
+                SfxBindings* pBindings = pDok->GetViewBindings();
bdede2a
+                if (pBindings)
bdede2a
+                    pBindings->Invalidate( SID_LINKS );             // Link-Manager enabled
bdede2a
+            }
bdede2a
 
bdede2a
-        if ( nRead > 0 )
bdede2a
+            //if the document was just loaded, but the ScDdeLink entry was missing, then
bdede2a
+            //don't update this link until the links are updated in response to the users
bdede2a
+            //decision
bdede2a
+            if (!pDok->HasLinkFormulaNeedingCheck())
bdede2a
+            {
bdede2a
+                pLink->Update();
bdede2a
+            }
bdede2a
+
bdede2a
+            if (pMyFormulaCell)
bdede2a
+            {
bdede2a
+                // StartListening after the Update to avoid circular references
bdede2a
+                pMyFormulaCell->StartListening(*pLink);
bdede2a
+            }
bdede2a
+        }
bdede2a
+        else
bdede2a
         {
bdede2a
-            aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
bdede2a
+            if (pMyFormulaCell)
bdede2a
+                pMyFormulaCell->StartListening(*pLink);
bdede2a
         }
bdede2a
 
bdede2a
-        xStream->closeInput();
bdede2a
+        //  If an new Error from Reschedule appears when the link is executed then reset the errorflag
bdede2a
+        if (pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE && !bWasError)
bdede2a
+            pMyFormulaCell->SetErrCode(FormulaError::NONE);
bdede2a
+
bdede2a
+        //  check the value
bdede2a
+        if (pLink->HasResult())
bdede2a
+            PushString(pLink->GetResult());
bdede2a
+        else
bdede2a
+            PushError(FormulaError::NoValue);
bdede2a
 
bdede2a
-        OUString aContent = OStringToOUString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
bdede2a
-        PushString( aContent );
bdede2a
+        pDok->EnableIdle(bOldEnabled);
bdede2a
+        mpLinkManager->CloseCachedComps();
bdede2a
     }
bdede2a
 }
bdede2a
 
bdede2a
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
bdede2a
index eae117c08434..18cbabb1cd93 100644
bdede2a
--- a/sc/source/core/tool/rangenam.cxx
bdede2a
+++ b/sc/source/core/tool/rangenam.cxx
bdede2a
@@ -64,9 +64,14 @@ ScRangeData::ScRangeData( ScDocument* pDok,
bdede2a
                 mnMaxCol    (-1)
bdede2a
 {
bdede2a
     if (!rSymbol.isEmpty())
bdede2a
-        CompileRangeData( rSymbol, pDoc->IsImportingXML());
bdede2a
+    {
bdede2a
         // Let the compiler set an error on unknown names for a subsequent
bdede2a
         // CompileUnresolvedXML().
bdede2a
+        const bool bImporting = pDoc->IsImportingXML();
bdede2a
+        CompileRangeData( rSymbol, bImporting);
bdede2a
+        if (bImporting)
bdede2a
+            pDoc->CheckLinkFormulaNeedingCheck( *pCode);
bdede2a
+    }
bdede2a
     else
bdede2a
     {
bdede2a
         // #i63513#/#i65690# don't leave pCode as NULL.
bdede2a
@@ -199,6 +204,7 @@ void ScRangeData::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt )
bdede2a
         // Don't let the compiler set an error for unknown names on final
bdede2a
         // compile, errors are handled by the interpreter thereafter.
bdede2a
         CompileRangeData( aSymbol, false);
bdede2a
+        rCxt.getDoc()->CheckLinkFormulaNeedingCheck( *pCode);
bdede2a
     }
bdede2a
 }
bdede2a
 
bdede2a
diff --git a/sc/source/core/tool/webservicelink.cxx b/sc/source/core/tool/webservicelink.cxx
bdede2a
new file mode 100644
bdede2a
index 000000000000..82310f2b1351
bdede2a
--- /dev/null
bdede2a
+++ b/sc/source/core/tool/webservicelink.cxx
bdede2a
@@ -0,0 +1,106 @@
bdede2a
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
bdede2a
+/*
bdede2a
+ * This file is part of the LibreOffice project.
bdede2a
+ *
bdede2a
+ * This Source Code Form is subject to the terms of the Mozilla Public
bdede2a
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
bdede2a
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
bdede2a
+ */
bdede2a
+
bdede2a
+#include <comphelper/fileformat.h>
bdede2a
+#include <comphelper/string.hxx>
bdede2a
+#include <osl/thread.h>
bdede2a
+#include <sfx2/linkmgr.hxx>
bdede2a
+#include <sfx2/bindings.hxx>
bdede2a
+
bdede2a
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
bdede2a
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
bdede2a
+#include <com/sun/star/io/XInputStream.hpp>
bdede2a
+
bdede2a
+#include <webservicelink.hxx>
bdede2a
+#include <brdcst.hxx>
bdede2a
+#include <document.hxx>
bdede2a
+#include <scmatrix.hxx>
bdede2a
+#include <patattr.hxx>
bdede2a
+#include <rechead.hxx>
bdede2a
+#include <rangeseq.hxx>
bdede2a
+#include <sc.hrc>
bdede2a
+#include <hints.hxx>
bdede2a
+
bdede2a
+ScWebServiceLink::ScWebServiceLink(ScDocument* pD, const OUString& rURL)
bdede2a
+    : ::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS, SotClipboardFormatId::STRING)
bdede2a
+    , pDoc(pD)
bdede2a
+    , aURL(rURL)
bdede2a
+    , bHasResult(false)
bdede2a
+{
bdede2a
+}
bdede2a
+
bdede2a
+ScWebServiceLink::~ScWebServiceLink() {}
bdede2a
+
bdede2a
+sfx2::SvBaseLink::UpdateResult ScWebServiceLink::DataChanged(const OUString&, const css::uno::Any&)
bdede2a
+{
bdede2a
+    aResult.clear();
bdede2a
+    bHasResult = false;
bdede2a
+
bdede2a
+    css::uno::Reference<css::ucb::XSimpleFileAccess3> xFileAccess(
bdede2a
+        css::ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()),
bdede2a
+        css::uno::UNO_QUERY);
bdede2a
+    if (!xFileAccess.is())
bdede2a
+        return ERROR_GENERAL;
bdede2a
+
bdede2a
+    css::uno::Reference<css::io::XInputStream> xStream;
bdede2a
+    try
bdede2a
+    {
bdede2a
+        xStream = xFileAccess->openFileRead(aURL);
bdede2a
+    }
bdede2a
+    catch (...)
bdede2a
+    {
bdede2a
+        // don't let any exceptions pass
bdede2a
+        return ERROR_GENERAL;
bdede2a
+    }
bdede2a
+    if (!xStream.is())
bdede2a
+        return ERROR_GENERAL;
bdede2a
+
bdede2a
+    const sal_Int32 BUF_LEN = 8000;
bdede2a
+    css::uno::Sequence<sal_Int8> buffer(BUF_LEN);
bdede2a
+    OStringBuffer aBuffer(64000);
bdede2a
+
bdede2a
+    sal_Int32 nRead = 0;
bdede2a
+    while ((nRead = xStream->readBytes(buffer, BUF_LEN)) == BUF_LEN)
bdede2a
+        aBuffer.append(reinterpret_cast<const char*>(buffer.getConstArray()), nRead);
bdede2a
+
bdede2a
+    if (nRead > 0)
bdede2a
+        aBuffer.append(reinterpret_cast<const char*>(buffer.getConstArray()), nRead);
bdede2a
+
bdede2a
+    xStream->closeInput();
bdede2a
+
bdede2a
+    aResult = OStringToOUString(aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8);
bdede2a
+    bHasResult = true;
bdede2a
+
bdede2a
+    //  Something happened...
bdede2a
+    if (HasListeners())
bdede2a
+    {
bdede2a
+        Broadcast(ScHint(SC_HINT_DATACHANGED, ScAddress()));
bdede2a
+        pDoc->TrackFormulas(); // must happen immediately
bdede2a
+        pDoc->StartTrackTimer();
bdede2a
+    }
bdede2a
+
bdede2a
+    return SUCCESS;
bdede2a
+}
bdede2a
+
bdede2a
+void ScWebServiceLink::ListenersGone()
bdede2a
+{
bdede2a
+    ScDocument* pStackDoc = pDoc; // member pDoc can't be used after removing the link
bdede2a
+
bdede2a
+    sfx2::LinkManager* pLinkMgr = pDoc->GetLinkManager();
bdede2a
+    pLinkMgr->Remove(this); // deletes this
bdede2a
+
bdede2a
+    if (pLinkMgr->GetLinks().empty()) // deleted the last one ?
bdede2a
+    {
bdede2a
+        SfxBindings* pBindings = pStackDoc->GetViewBindings(); // don't use member pDoc!
bdede2a
+        if (pBindings)
bdede2a
+            pBindings->Invalidate(SID_LINKS);
bdede2a
+    }
bdede2a
+}
bdede2a
+
bdede2a
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
bdede2a
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx
bdede2a
index 67e7657f3428..889225c364bc 100644
bdede2a
--- a/sc/source/filter/excel/excform.cxx
bdede2a
+++ b/sc/source/filter/excel/excform.cxx
bdede2a
@@ -156,6 +156,7 @@ void ImportExcel::Formula(
bdede2a
     {
bdede2a
         pCell = new ScFormulaCell(&rDoc.getDoc(), aScPos, *pResult);
bdede2a
         pCell->GetCode()->WrapReference(aScPos, EXC_MAXCOL8, EXC_MAXROW8);
bdede2a
+        rDoc.getDoc().CheckLinkFormulaNeedingCheck( *pCell->GetCode());
bdede2a
         rDoc.getDoc().EnsureTable(aScPos.Tab());
bdede2a
         rDoc.setFormulaCell(aScPos, pCell);
bdede2a
         SetLastFormula(aScPos.Col(), aScPos.Row(), fCurVal, nXF, pCell);
bdede2a
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx
bdede2a
index ef3d09ae1c8b..ff3387bf916b 100644
bdede2a
--- a/sc/source/filter/excel/excform8.cxx
bdede2a
+++ b/sc/source/filter/excel/excform8.cxx
bdede2a
@@ -730,6 +730,7 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
bdede2a
                                         << nMerk0 << ocClose;
bdede2a
                                 aPool >> aStack;
bdede2a
                                 pExtName->CreateDdeData( GetDoc(), aApplic, aTopic );
bdede2a
+                                GetDoc().SetLinkFormulaNeedingCheck(true);
bdede2a
                             }
bdede2a
                         }
bdede2a
                         break;
bdede2a
diff --git a/sc/source/filter/excel/impop.cxx b/sc/source/filter/excel/impop.cxx
bdede2a
index 01b5b736951e..a76a81db3ff8 100644
bdede2a
--- a/sc/source/filter/excel/impop.cxx
bdede2a
+++ b/sc/source/filter/excel/impop.cxx
bdede2a
@@ -866,6 +866,7 @@ void ImportExcel::Shrfmla()
bdede2a
 
bdede2a
     ScFormulaCell* pCell = new ScFormulaCell(pD, aPos, *pErgebnis);
bdede2a
     pCell->GetCode()->WrapReference(aPos, EXC_MAXCOL8, EXC_MAXROW8);
bdede2a
+    rDoc.getDoc().CheckLinkFormulaNeedingCheck( *pCell->GetCode());
bdede2a
     rDoc.getDoc().EnsureTable(aPos.Tab());
bdede2a
     rDoc.setFormulaCell(aPos, pCell);
bdede2a
     pCell->SetNeedNumberFormat(false);
bdede2a
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
bdede2a
index bb80a929b35f..d2418806da53 100644
bdede2a
--- a/sc/source/filter/excel/xicontent.cxx
bdede2a
+++ b/sc/source/filter/excel/xicontent.cxx
bdede2a
@@ -662,7 +662,10 @@ void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
bdede2a
         rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_CondFormat );
bdede2a
         // formula converter owns pTokArr -> create a copy of the token array
bdede2a
         if( pTokArr )
bdede2a
+        {
bdede2a
             xTokArr1.reset( pTokArr->Clone() );
bdede2a
+            GetDocRef().CheckLinkFormulaNeedingCheck( *xTokArr1);
bdede2a
+        }
bdede2a
     }
bdede2a
 
bdede2a
     ::std::unique_ptr< ScTokenArray > pTokArr2;
bdede2a
@@ -673,7 +676,10 @@ void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
bdede2a
         rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_CondFormat );
bdede2a
         // formula converter owns pTokArr -> create a copy of the token array
bdede2a
         if( pTokArr )
bdede2a
+        {
bdede2a
             pTokArr2.reset( pTokArr->Clone() );
bdede2a
+            GetDocRef().CheckLinkFormulaNeedingCheck( *pTokArr2);
bdede2a
+        }
bdede2a
     }
bdede2a
 
bdede2a
     // *** create the Calc conditional formatting ***
bdede2a
diff --git a/sc/source/filter/excel/xiname.cxx b/sc/source/filter/excel/xiname.cxx
bdede2a
index 7189c2a0a2f2..efc181921091 100644
bdede2a
--- a/sc/source/filter/excel/xiname.cxx
bdede2a
+++ b/sc/source/filter/excel/xiname.cxx
bdede2a
@@ -265,7 +265,10 @@ void XclImpName::InsertName(const ScTokenArray* pArray)
bdede2a
         }
bdede2a
     }
bdede2a
     if (pData)
bdede2a
+    {
bdede2a
+        GetDoc().CheckLinkFormulaNeedingCheck( *pData->GetCode());
bdede2a
         mpScData = pData;               // cache for later use
bdede2a
+    }
bdede2a
 }
bdede2a
 
bdede2a
 XclImpNameManager::XclImpNameManager( const XclImpRoot& rRoot ) :
bdede2a
diff --git a/sc/source/filter/oox/condformatbuffer.cxx b/sc/source/filter/oox/condformatbuffer.cxx
bdede2a
index 1d0dd13fd773..aa8fbbaa4d96 100644
bdede2a
--- a/sc/source/filter/oox/condformatbuffer.cxx
bdede2a
+++ b/sc/source/filter/oox/condformatbuffer.cxx
bdede2a
@@ -874,11 +874,13 @@ void CondFormatRule::finalizeImport()
bdede2a
         {
bdede2a
             pTokenArray2.reset(new ScTokenArray());
bdede2a
             ScTokenConversion::ConvertToTokenArray( rDoc, *pTokenArray2.get(), maModel.maFormulas[ 1 ] );
bdede2a
+            rDoc.CheckLinkFormulaNeedingCheck( *pTokenArray2.get());
bdede2a
         }
bdede2a
 
bdede2a
         ScTokenArray aTokenArray;
bdede2a
         OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
bdede2a
         ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, maModel.maFormulas[ 0 ] );
bdede2a
+        rDoc.CheckLinkFormulaNeedingCheck( aTokenArray);
bdede2a
         ScCondFormatEntry* pNewEntry = new ScCondFormatEntry(eOperator,
bdede2a
                                             &aTokenArray, pTokenArray2.get(), &rDoc, aPos, aStyleName);
bdede2a
         mpFormat->AddEntry(pNewEntry);
bdede2a
diff --git a/sc/source/filter/oox/defnamesbuffer.cxx b/sc/source/filter/oox/defnamesbuffer.cxx
bdede2a
index 79457ab57e5f..a1d10906c687 100644
bdede2a
--- a/sc/source/filter/oox/defnamesbuffer.cxx
bdede2a
+++ b/sc/source/filter/oox/defnamesbuffer.cxx
bdede2a
@@ -38,6 +38,7 @@
bdede2a
 #include "tokenarray.hxx"
bdede2a
 #include "tokenuno.hxx"
bdede2a
 #include "compiler.hxx"
bdede2a
+#include "document.hxx"
bdede2a
 
bdede2a
 namespace oox {
bdede2a
 namespace xls {
bdede2a
@@ -334,6 +335,7 @@ std::unique_ptr<ScTokenArray> DefinedName::getScTokens(
bdede2a
     // after, a resulting error must be reset.
bdede2a
     FormulaError nErr = pArray->GetCodeError();
bdede2a
     aCompiler.CompileTokenArray();
bdede2a
+    getScDocument().CheckLinkFormulaNeedingCheck( *pArray);
bdede2a
     pArray->DelRPN();
bdede2a
     pArray->SetCodeError(nErr);
bdede2a
 
bdede2a
diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx
bdede2a
index 003d0b96769b..bfa229292775 100644
bdede2a
--- a/sc/source/filter/oox/formulabuffer.cxx
bdede2a
+++ b/sc/source/filter/oox/formulabuffer.cxx
bdede2a
@@ -223,6 +223,10 @@ void applyCellFormulas(
bdede2a
             continue;
bdede2a
 
bdede2a
         aCompiler.CompileTokenArray(); // Generate RPN tokens.
bdede2a
+
bdede2a
+        // Check if ocDde/ocWebservice is in any formula for external links warning.
bdede2a
+        rDoc.getDoc().CheckLinkFormulaNeedingCheck(*pCode);
bdede2a
+
bdede2a
         ScFormulaCell* pCell = new ScFormulaCell(&rDoc.getDoc(), aPos, pCode);
bdede2a
         rDoc.setFormulaCell(aPos, pCell);
bdede2a
         rCache.store(aPos, pCell);
bdede2a
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
bdede2a
index 81dbf194d0c7..a2b1b11ee646 100644
bdede2a
--- a/sc/source/ui/docshell/docsh4.cxx
bdede2a
+++ b/sc/source/ui/docshell/docsh4.cxx
bdede2a
@@ -450,7 +450,7 @@ void ScDocShell::Execute( SfxRequest& rReq )
bdede2a
                     ReloadTabLinks();
bdede2a
                     aDocument.UpdateExternalRefLinks(GetActiveDialogParent());
bdede2a
 
bdede2a
-                    bool bAnyDde = aDocument.GetDocLinkManager().updateDdeOrOleLinks(GetActiveDialogParent());
bdede2a
+                    bool bAnyDde = aDocument.GetDocLinkManager().updateDdeOrOleOrWebServiceLinks(GetActiveDialogParent());
bdede2a
 
bdede2a
                     if (bAnyDde)
bdede2a
                     {
bdede2a
@@ -472,6 +472,8 @@ void ScDocShell::Execute( SfxRequest& rReq )
bdede2a
                     rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
bdede2a
                     rReq.Ignore();
bdede2a
                 }
bdede2a
+
bdede2a
+                rDoc.SetLinkFormulaNeedingCheck(false);
bdede2a
             }
bdede2a
             break;
bdede2a
 
bdede2a
diff --git a/sc/source/ui/docshell/documentlinkmgr.cxx b/sc/source/ui/docshell/documentlinkmgr.cxx
bdede2a
index 520b8542afc0..b8a9df65cb6b 100644
bdede2a
--- a/sc/source/ui/docshell/documentlinkmgr.cxx
bdede2a
+++ b/sc/source/ui/docshell/documentlinkmgr.cxx
bdede2a
@@ -20,6 +20,7 @@
bdede2a
 #include <documentlinkmgr.hxx>
bdede2a
 #include <datastream.hxx>
bdede2a
 #include <ddelink.hxx>
bdede2a
+#include <webservicelink.hxx>
bdede2a
 #include <sc.hrc>
bdede2a
 #include <scresid.hxx>
bdede2a
 
bdede2a
@@ -115,15 +116,15 @@ bool DocumentLinkManager::idleCheckLinks()
bdede2a
 
bdede2a
 bool DocumentLinkManager::hasDdeLinks() const
bdede2a
 {
bdede2a
-    return hasDdeOrOleLinks(true, false);
bdede2a
+    return hasDdeOrOleOrWebServiceLinks(true, false, false);
bdede2a
 }
bdede2a
 
bdede2a
-bool DocumentLinkManager::hasDdeOrOleLinks() const
bdede2a
+bool DocumentLinkManager::hasDdeOrOleOrWebServiceLinks() const
bdede2a
 {
bdede2a
-    return hasDdeOrOleLinks(true, true);
bdede2a
+    return hasDdeOrOleOrWebServiceLinks(true, true, true);
bdede2a
 }
bdede2a
 
bdede2a
-bool DocumentLinkManager::hasDdeOrOleLinks(bool bDde, bool bOle) const
bdede2a
+bool DocumentLinkManager::hasDdeOrOleOrWebServiceLinks(bool bDde, bool bOle, bool bWebService) const
bdede2a
 {
bdede2a
     if (!mpImpl->mpLinkManager)
bdede2a
         return false;
bdede2a
@@ -136,12 +137,14 @@ bool DocumentLinkManager::hasDdeOrOleLinks(bool bDde, bool bOle) const
bdede2a
             return true;
bdede2a
         if (bOle && dynamic_cast<SdrEmbedObjectLink*>(pBase))
bdede2a
             return true;
bdede2a
+        if (bWebService && dynamic_cast<ScWebServiceLink*>(pBase))
bdede2a
+            return true;
bdede2a
     }
bdede2a
 
bdede2a
     return false;
bdede2a
 }
bdede2a
 
bdede2a
-bool DocumentLinkManager::updateDdeOrOleLinks( vcl::Window* pWin )
bdede2a
+bool DocumentLinkManager::updateDdeOrOleOrWebServiceLinks(vcl::Window* pWin)
bdede2a
 {
bdede2a
     if (!mpImpl->mpLinkManager)
bdede2a
         return false;
bdede2a
@@ -163,6 +166,13 @@ bool DocumentLinkManager::updateDdeOrOleLinks( vcl::Window* pWin )
bdede2a
             continue;
bdede2a
         }
bdede2a
 
bdede2a
+        ScWebServiceLink* pWebserviceLink = dynamic_cast<ScWebServiceLink*>(pBase);
bdede2a
+        if (pWebserviceLink)
bdede2a
+        {
bdede2a
+            pWebserviceLink->Update();
bdede2a
+            continue;
bdede2a
+        }
bdede2a
+
bdede2a
         ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>(pBase);
bdede2a
         if (!pDdeLink)
bdede2a
             continue;
bdede2a
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
bdede2a
index e8f4491ae26e..17fb575a162f 100644
bdede2a
--- a/sc/source/ui/view/tabvwsh4.cxx
bdede2a
+++ b/sc/source/ui/view/tabvwsh4.cxx
bdede2a
@@ -1575,7 +1575,7 @@ void ScTabViewShell::Construct( TriState nForceDesignMode )
bdede2a
             if (!bLink)
bdede2a
             {
bdede2a
                 const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
bdede2a
-                if (rMgr.hasDdeOrOleLinks() || rDoc.HasAreaLinks())
bdede2a
+                if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks() || rMgr.hasDdeOrOleOrWebServiceLinks())
bdede2a
                     bLink = true;
bdede2a
             }
bdede2a
             if (bLink)
bdede2a
-- 
bdede2a
2.14.3
bdede2a