Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/appl/linkmgr2.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
#include <sal/config.h>
21
22
#include <comphelper/lok.hxx>
23
#include <comphelper/string.hxx>
24
#include <sfx2/linkmgr.hxx>
25
#include <sfx2/sfxsids.hrc>
26
#include <com/sun/star/document/UpdateDocMode.hpp>
27
#include <officecfg/Office/Common.hxx>
28
#include <osl/file.hxx>
29
#include <sfx2/objsh.hxx>
30
#include <svl/itemset.hxx>
31
#include <svl/urihelper.hxx>
32
#include <sot/formats.hxx>
33
#include <tools/urlobj.hxx>
34
#include <sot/exchange.hxx>
35
#include <tools/debug.hxx>
36
#include <tools/stream.hxx>
37
#include <vcl/filter/SvmReader.hxx>
38
#include <vcl/svapp.hxx>
39
#include <vcl/vclenum.hxx>
40
#include <vcl/weld/MessageDialog.hxx>
41
#include <vcl/gdimtf.hxx>
42
#include <sfx2/lnkbase.hxx>
43
#include <sfx2/app.hxx>
44
#include <vcl/graph.hxx>
45
#include <svl/stritem.hxx>
46
#include <svl/eitem.hxx>
47
#include <svl/intitem.hxx>
48
#include <i18nlangtag/languagetag.hxx>
49
#include <vcl/dibtools.hxx>
50
#include <unotools/charclass.hxx>
51
#include <unotools/securityoptions.hxx>
52
#include <vcl/GraphicLoader.hxx>
53
#include <vcl/TypeSerializer.hxx>
54
55
#include "fileobj.hxx"
56
#include "impldde.hxx"
57
#include <sfx2/strings.hrc>
58
#include <sfx2/sfxresid.hxx>
59
60
#include <com/sun/star/lang/XComponent.hpp>
61
#include <com/sun/star/util/XCloseable.hpp>
62
63
using ::com::sun::star::uno::UNO_QUERY;
64
using ::com::sun::star::uno::Reference;
65
using ::com::sun::star::lang::XComponent;
66
using ::com::sun::star::util::XCloseable;
67
68
namespace sfx2
69
{
70
71
namespace {
72
73
class SvxInternalLink : public sfx2::SvLinkSource
74
{
75
public:
76
0
    SvxInternalLink() {}
77
78
    virtual bool Connect( sfx2::SvBaseLink* ) override;
79
};
80
81
}
82
83
LinkManager::LinkManager(SfxObjectShell* p)
84
106k
    : pPersist( p )
85
106k
{
86
106k
}
87
88
LinkManager::~LinkManager()
89
106k
{
90
106k
    for(tools::SvRef<SvBaseLink> & rTmp : aLinkTbl)
91
0
    {
92
0
        if( rTmp.is() )
93
0
        {
94
0
            rTmp->Disconnect();
95
0
            rTmp->SetLinkManager( nullptr );
96
0
        }
97
0
    }
98
106k
}
99
100
void LinkManager::InsertCachedComp(const Reference<XComponent>& xComp)
101
0
{
102
0
    maCachedComps.push_back(xComp);
103
0
}
104
105
void LinkManager::CloseCachedComps()
106
2
{
107
2
    for (const auto& rxCachedComp : maCachedComps)
108
0
    {
109
0
        Reference<XCloseable> xCloseable(rxCachedComp, UNO_QUERY);
110
0
        if (!xCloseable.is())
111
0
            continue;
112
113
0
        xCloseable->close(true);
114
0
    }
115
2
    maCachedComps.clear();
116
2
}
117
118
void LinkManager::Remove( SvBaseLink const *pLink )
119
103k
{
120
    // No duplicate links inserted
121
103k
    bool bFound = false;
122
146k
    for( size_t n = 0; n < aLinkTbl.size(); )
123
59.0k
    {
124
59.0k
        tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
125
59.0k
        if( pLink == rTmp.get() )
126
16.1k
        {
127
16.1k
            rTmp->Disconnect();
128
16.1k
            rTmp->SetLinkManager( nullptr );
129
16.1k
            rTmp.clear();
130
16.1k
            bFound = true;
131
16.1k
        }
132
133
        // Remove empty ones if they exist
134
59.0k
        if( !rTmp.is() )
135
16.1k
        {
136
16.1k
            aLinkTbl.erase( aLinkTbl.begin() + n );
137
16.1k
            if( bFound )
138
16.1k
                return ;
139
16.1k
        }
140
42.9k
        else
141
42.9k
            ++n;
142
59.0k
    }
143
103k
}
144
145
void LinkManager::Remove( size_t nPos, size_t nCnt )
146
5.24k
{
147
5.24k
    if( !nCnt || nPos >= aLinkTbl.size() )
148
0
        return;
149
150
5.24k
    if (sal::static_int_cast<size_t>(nPos + nCnt) > aLinkTbl.size())
151
0
        nCnt = aLinkTbl.size() - nPos;
152
153
101k
    for( size_t n = nPos; n < nPos + nCnt; ++n)
154
96.5k
    {
155
96.5k
        tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
156
96.5k
        if( rTmp.is() )
157
96.5k
        {
158
96.5k
            rTmp->Disconnect();
159
96.5k
            rTmp->SetLinkManager( nullptr );
160
96.5k
        }
161
96.5k
    }
162
5.24k
    aLinkTbl.erase( aLinkTbl.begin() + nPos, aLinkTbl.begin() + nPos + nCnt );
163
5.24k
}
164
165
bool LinkManager::Insert( SvBaseLink* pLink )
166
112k
{
167
7.09M
    for( size_t n = 0; n < aLinkTbl.size(); ++n )
168
6.97M
    {
169
6.97M
        tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
170
6.97M
        if( !rTmp.is() )
171
0
        {
172
0
            aLinkTbl.erase( aLinkTbl.begin() + n-- );
173
0
        }
174
6.97M
        else if( pLink == rTmp.get() )
175
0
            return false; // No duplicate links inserted
176
6.97M
    }
177
178
112k
    pLink->SetLinkManager( this );
179
112k
    aLinkTbl.emplace_back(pLink );
180
112k
    return true;
181
112k
}
182
183
bool LinkManager::InsertLink( SvBaseLink * pLink,
184
                                SvBaseLinkObjectType nObjType,
185
                                SfxLinkUpdateMode nUpdateMode,
186
                                const OUString* pName )
187
112k
{
188
    // This First
189
112k
    pLink->SetObjType( nObjType );
190
112k
    if( pName )
191
112k
        pLink->SetName( *pName );
192
112k
    pLink->SetUpdateMode( nUpdateMode );
193
112k
    return Insert( pLink );
194
112k
}
195
196
void LinkManager::InsertDDELink( SvBaseLink * pLink,
197
                                    const OUString& rServer,
198
                                    std::u16string_view rTopic,
199
                                    std::u16string_view rItem )
200
0
{
201
0
    if( !isClientType( pLink->GetObjType() ) )
202
0
        return;
203
204
0
    OUString sCmd;
205
0
    ::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
206
207
0
    pLink->SetObjType( SvBaseLinkObjectType::ClientDde );
208
0
    pLink->SetName( sCmd );
209
0
    Insert( pLink );
210
0
}
211
212
void LinkManager::InsertDDELink( SvBaseLink * pLink )
213
0
{
214
0
    DBG_ASSERT( isClientType(pLink->GetObjType()), "no OBJECT_CLIENT_SO" );
215
0
    if( !isClientType( pLink->GetObjType() ) )
216
0
        return;
217
218
0
    if( pLink->GetObjType() == SvBaseLinkObjectType::ClientSo )
219
0
        pLink->SetObjType( SvBaseLinkObjectType::ClientDde );
220
221
0
    Insert( pLink );
222
0
}
223
224
// Obtain the string for the dialog
225
bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
226
                                        OUString* pType,
227
                                        OUString* pFile,
228
                                        OUString* pLinkStr,
229
                                        OUString* pFilter )
230
92.2k
{
231
92.2k
    bool bRet = false;
232
92.2k
    const OUString& sLNm( pLink->GetLinkSourceName() );
233
92.2k
    if( !sLNm.isEmpty() )
234
92.2k
    {
235
92.2k
        switch( pLink->GetObjType() )
236
92.2k
        {
237
8.85k
            case SvBaseLinkObjectType::ClientFile:
238
92.2k
            case SvBaseLinkObjectType::ClientGraphic:
239
92.2k
            case SvBaseLinkObjectType::ClientOle:
240
92.2k
                {
241
92.2k
                    sal_Int32 nPos = 0;
242
92.2k
                    OUString sFile( sLNm.getToken( 0, ::sfx2::cTokenSeparator, nPos ) );
243
92.2k
                    OUString sRange( sLNm.getToken( 0, ::sfx2::cTokenSeparator, nPos ) );
244
245
92.2k
                    if( pFile )
246
92.2k
                        *pFile = sFile;
247
92.2k
                    if( pLinkStr )
248
236
                        *pLinkStr = sRange;
249
92.2k
                    if( pFilter )
250
92.2k
                        *pFilter = nPos == -1 ? OUString() : sLNm.copy(nPos);
251
252
92.2k
                    if( pType )
253
0
                    {
254
0
                        SvBaseLinkObjectType nObjType = pLink->GetObjType();
255
0
                        *pType = SfxResId(
256
0
                                    ( SvBaseLinkObjectType::ClientFile == nObjType || SvBaseLinkObjectType::ClientOle == nObjType )
257
0
                                            ? RID_SVXSTR_FILELINK
258
0
                                            : RID_SVXSTR_GRAPHICLINK);
259
0
                    }
260
92.2k
                    bRet = true;
261
92.2k
                }
262
92.2k
                break;
263
0
            case SvBaseLinkObjectType::ClientDde:
264
0
                {
265
0
                    sal_Int32 nTmp = 0;
266
0
                    OUString sServer( sLNm.getToken( 0, cTokenSeparator, nTmp ) );
267
0
                    OUString sTopic( sLNm.getToken( 0, cTokenSeparator, nTmp ) );
268
0
                    OUString sLinkStr( sLNm.getToken(0, cTokenSeparator, nTmp) );
269
270
0
                    if( pType )
271
0
                        *pType = sServer;
272
0
                    if( pFile )
273
0
                        *pFile = sTopic;
274
0
                    if( pLinkStr )
275
0
                        *pLinkStr = sLinkStr;
276
0
                    bRet = true;
277
0
                }
278
0
                break;
279
0
            default:
280
0
                break;
281
92.2k
        }
282
92.2k
    }
283
284
92.2k
    return bRet;
285
92.2k
}
286
287
static void disallowAllLinksUpdate(SvBaseLink* pShellProvider)
288
0
{
289
0
    if (SfxObjectShell* pShell = pShellProvider->GetLinkManager()->GetPersist())
290
0
        pShell->getEmbeddedObjectContainer().setUserAllowsLinkUpdate(false);
291
0
}
292
293
void LinkManager::UpdateAllLinks(
294
    bool bAskUpdate,
295
    weld::Window* pParentWin,
296
    OUString const & referer )
297
0
{
298
    // when active content is disabled don't bother updating all links
299
    // also (when bAskUpdate == true) don't show the pop up.
300
0
    if(officecfg::Office::Common::Security::Scripting::DisableActiveContent::get()
301
0
       || SvtSecurityOptions::isUntrustedReferer(referer))
302
0
        return;
303
304
    // First make a copy of the array in order to update links
305
    // links in ... no contact between them!
306
0
    std::vector<SvBaseLink*> aTmpArr;
307
0
    for( size_t n = 0; n < aLinkTbl.size(); ++n )
308
0
    {
309
0
        tools::SvRef<SvBaseLink>& rLink = aLinkTbl[ n ];
310
0
        if( !rLink.is() )
311
0
        {
312
0
            Remove( n-- );
313
0
            continue;
314
0
        }
315
0
        aTmpArr.push_back( rLink.get() );
316
0
    }
317
318
0
    for(SvBaseLink* pLink : aTmpArr)
319
0
    {
320
        // search first in the array after the entry
321
0
        bool bFound = false;
322
0
        for(const tools::SvRef<SvBaseLink> & i : aLinkTbl)
323
0
            if( pLink == i.get() )
324
0
            {
325
0
                bFound = true;
326
0
                break;
327
0
            }
328
329
0
        if( !bFound )
330
0
            continue;  // was not available!
331
332
0
        if( !pLink->IsVisible() )
333
0
            continue;
334
335
0
        if( bAskUpdate )
336
0
        {
337
0
            if (comphelper::LibreOfficeKit::isActive())
338
0
            {
339
                // only one document in jail, no update possible
340
0
                disallowAllLinksUpdate(pLink);
341
0
                return;
342
0
            }
343
344
0
            OUString aMsg = SfxResId(STR_QUERY_UPDATE_LINKS);
345
0
            INetURLObject aURL(pPersist->getDocumentBaseURL());
346
            // tdf#168089 - don't URL encode filename for the update links confirmation dialog
347
0
            aMsg = aMsg.replaceFirst("%{filename}",
348
0
                                     aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
349
350
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParentWin,
351
0
                                                           VclMessageType::Question, VclButtonsType::YesNo, aMsg));
352
0
            xQueryBox->set_default_response(RET_YES);
353
354
0
            int nRet = xQueryBox->run();
355
0
            if( RET_YES != nRet )
356
0
            {
357
0
                disallowAllLinksUpdate(pLink);
358
0
                return ;        // nothing should be updated
359
0
            }
360
0
            bAskUpdate = false;  // once is enough
361
0
        }
362
363
0
        pLink->Update();
364
0
    }
365
0
    CloseCachedComps();
366
0
}
367
368
SvLinkSourceRef LinkManager::CreateObj( SvBaseLink const * pLink )
369
90.4k
{
370
90.4k
    switch( pLink->GetObjType() )
371
90.4k
    {
372
8.62k
        case SvBaseLinkObjectType::ClientFile:
373
90.4k
        case SvBaseLinkObjectType::ClientGraphic:
374
90.4k
        case SvBaseLinkObjectType::ClientOle:
375
90.4k
            return new SvFileObject;
376
0
        case SvBaseLinkObjectType::Internal:
377
0
            if(officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
378
0
                return SvLinkSourceRef();
379
0
            return new SvxInternalLink;
380
0
        case SvBaseLinkObjectType::ClientDde:
381
0
            if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
382
0
                return SvLinkSourceRef();
383
0
            return new SvDDEObject;
384
0
        default:
385
0
            return SvLinkSourceRef();
386
90.4k
       }
387
90.4k
}
388
389
bool LinkManager::InsertServer( SvLinkSource* pObj )
390
0
{
391
    // no duplicate inserts
392
0
    if( !pObj )
393
0
        return false;
394
395
0
    return aServerTbl.insert( pObj ).second;
396
0
}
397
398
void LinkManager::RemoveServer( SvLinkSource* pObj )
399
0
{
400
0
    aServerTbl.erase( pObj );
401
0
}
402
403
void MakeLnkName( OUString& rName, const OUString* pType, std::u16string_view rFile,
404
                    std::u16string_view rLink, const OUString* pFilter )
405
0
{
406
0
    if( pType )
407
0
    {
408
0
        rName = comphelper::string::strip(*pType, ' ')
409
0
            + OUStringChar(cTokenSeparator);
410
0
    }
411
0
    else
412
0
        rName.clear();
413
414
0
    rName += rFile;
415
416
0
    rName = comphelper::string::strip(rName, ' ')
417
0
        + OUStringChar(cTokenSeparator);
418
0
    rName = comphelper::string::strip(rName, ' ') + rLink;
419
0
    if( pFilter )
420
0
    {
421
0
        rName += OUStringChar(cTokenSeparator) + *pFilter;
422
0
        rName = comphelper::string::strip(rName, ' ');
423
0
    }
424
0
}
425
426
void LinkManager::ReconnectDdeLink(SfxObjectShell& rServer)
427
0
{
428
0
    SfxMedium* pMed = rServer.GetMedium();
429
0
    if (!pMed)
430
0
        return;
431
432
0
    const ::sfx2::SvBaseLinks& rLinks = GetLinks();
433
0
    size_t n = rLinks.size();
434
435
0
    for (size_t i = 0; i < n; ++i)
436
0
    {
437
0
        ::sfx2::SvBaseLink* p = rLinks[i].get();
438
0
        OUString aType, aFile, aLink, aFilter;
439
0
        if (!GetDisplayNames(p, &aType, &aFile, &aLink, &aFilter))
440
0
            continue;
441
442
0
        if (aType != "soffice")
443
            // DDE connections between OOo apps are always named 'soffice'.
444
0
            continue;
445
446
0
        OUString aTmp;
447
0
        OUString aURL = aFile;
448
0
        if (osl::FileBase::getFileURLFromSystemPath(aFile, aTmp)
449
0
            == osl::FileBase::E_None)
450
0
            aURL = aTmp;
451
452
0
        if (!aURL.equalsIgnoreAsciiCase(pMed->GetName()))
453
            // This DDE link is not associated with this server shell...  Skip it.
454
0
            continue;
455
456
0
        if (aLink.isEmpty())
457
0
            continue;
458
459
0
        LinkServerShell(aLink, rServer, *p);
460
0
    }
461
0
}
462
463
void LinkManager::LinkServerShell(const OUString& rPath, SfxObjectShell& rServer, ::sfx2::SvBaseLink& rLink)
464
0
{
465
0
    ::sfx2::SvLinkSource* pSrvSrc = rServer.DdeCreateLinkSource(rPath);
466
0
    if (pSrvSrc)
467
0
    {
468
0
        css::datatransfer::DataFlavor aFl;
469
0
        SotExchange::GetFormatDataFlavor(rLink.GetContentType(), aFl);
470
0
        rLink.SetObj(pSrvSrc);
471
0
        pSrvSrc->AddDataAdvise(
472
0
            &rLink, aFl.MimeType,
473
0
            SfxLinkUpdateMode::ONCALL == rLink.GetUpdateMode() ? ADVISEMODE_ONLYONCE : 0);
474
0
    }
475
0
}
476
477
void LinkManager::InsertFileLink(
478
    sfx2::SvBaseLink& rLink, SvBaseLinkObjectType nFileType, std::u16string_view rFileNm,
479
    const OUString* pFilterNm, const OUString* pRange)
480
112k
{
481
112k
    if (!isClientType(rLink.GetObjType()))
482
0
        return;
483
484
112k
    OUStringBuffer aBuf(64);
485
112k
    aBuf.append(rFileNm + OUStringChar(sfx2::cTokenSeparator));
486
487
112k
    if (pRange)
488
382
        aBuf.append(*pRange);
489
490
112k
    if (pFilterNm)
491
329
    {
492
329
        aBuf.append(OUStringChar(sfx2::cTokenSeparator) + *pFilterNm);
493
329
    }
494
495
112k
    OUString aCmd = aBuf.makeStringAndClear();
496
112k
    InsertLink(&rLink, nFileType, SfxLinkUpdateMode::ONCALL, &aCmd);
497
112k
}
498
499
// A transfer is aborted, so cancel all download media
500
// (for now this is only of interest for the file links!)
501
void LinkManager::CancelTransfers()
502
4.14k
{
503
504
4.14k
    const sfx2::SvBaseLinks& rLnks = GetLinks();
505
4.59k
    for( size_t n = rLnks.size(); n; )
506
448
    {
507
448
        const sfx2::SvBaseLink& rLnk = *rLnks[--n];
508
448
        if (isClientFileType(rLnk.GetObjType()))
509
448
        {
510
448
            if (SvFileObject* pFileObj = static_cast<SvFileObject*>(rLnk.GetObj()))
511
448
                pFileObj->CancelTransfers();
512
448
        }
513
448
    }
514
4.14k
}
515
516
// For the purpose of sending Status information from the file object to
517
// the base link, there exist a dedicated ClipBoardId. The SvData-object
518
// gets the appropriate information as a string
519
// For now this is required for file object in conjunction with JavaScript
520
// - needs information about Load/Abort/Error
521
SotClipboardFormatId LinkManager::RegisterStatusInfoId()
522
21.3k
{
523
21.3k
    static SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
524
525
21.3k
    if( nFormat == SotClipboardFormatId::NONE )
526
2
    {
527
2
        nFormat = SotExchange::RegisterFormatName(
528
2
                    u"StatusInfo from SvxInternalLink"_ustr);
529
2
    }
530
21.3k
    return nFormat;
531
21.3k
}
532
533
bool LinkManager::GetGraphicFromAny(std::u16string_view rMimeType,
534
                                    const css::uno::Any & rValue,
535
                                    Graphic& rGraphic,
536
                                    weld::Window* pParentWin)
537
20.8k
{
538
20.8k
    bool bRet = false;
539
540
20.8k
    if (!rValue.hasValue())
541
0
        return bRet;
542
543
20.8k
    if (rValue.has<OUString>())
544
20.8k
    {
545
20.8k
        OUString sReferer;
546
20.8k
        SfxObjectShell* sh = GetPersist();
547
20.8k
        if (sh && sh->HasName())
548
0
            sReferer = sh->GetMedium()->GetName();
549
550
20.8k
        OUString sURL = rValue.get<OUString>();
551
20.8k
        if (!SvtSecurityOptions::isUntrustedReferer(sReferer) &&
552
20.8k
            !INetURLObject(sURL).IsExoticProtocol())
553
20.8k
        {
554
20.8k
            rGraphic = vcl::graphic::loadFromURL(sURL, pParentWin);
555
20.8k
        }
556
20.8k
        if (rGraphic.IsNone())
557
20.8k
            rGraphic.SetDefaultType();
558
20.8k
        rGraphic.setOriginURL(sURL);
559
20.8k
        return true;
560
20.8k
    }
561
0
    else if (rValue.has<css::uno::Sequence<sal_Int8>>())
562
0
    {
563
0
        auto aSeq = rValue.get<css::uno::Sequence<sal_Int8>>();
564
565
0
        SvMemoryStream aMemStm( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(),
566
0
                                StreamMode::READ );
567
0
        aMemStm.Seek( 0 );
568
569
0
        switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
570
0
        {
571
0
        case SotClipboardFormatId::SVXB:
572
0
            {
573
0
                TypeSerializer aSerializer(aMemStm);
574
0
                aSerializer.readGraphic(rGraphic);
575
0
                bRet = true;
576
0
            }
577
0
            break;
578
0
        case SotClipboardFormatId::GDIMETAFILE:
579
0
            {
580
0
                GDIMetaFile aMtf;
581
0
                SvmReader aReader( aMemStm );
582
0
                aReader.Read( aMtf );
583
0
                rGraphic = aMtf;
584
0
                bRet = true;
585
0
            }
586
0
            break;
587
0
        case SotClipboardFormatId::BITMAP:
588
0
            {
589
0
                Bitmap aBmp;
590
0
                ReadDIB(aBmp, aMemStm, true);
591
0
                rGraphic = aBmp;
592
0
                bRet = true;
593
0
            }
594
0
            break;
595
0
        default: break;
596
0
        }
597
0
    }
598
0
    return bRet;
599
20.8k
}
600
601
static OUString lcl_DDE_RelToAbs( const OUString& rTopic, std::u16string_view rBaseURL )
602
0
{
603
0
    OUString sRet;
604
0
    INetURLObject aURL( rTopic );
605
0
    if( INetProtocol::NotValid == aURL.GetProtocol() )
606
0
        osl::FileBase::getFileURLFromSystemPath(rTopic, sRet);
607
0
    if( sRet.isEmpty() )
608
0
        sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl() );
609
0
    return sRet;
610
0
}
611
612
bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
613
0
{
614
0
    SfxObjectShell* pFndShell = nullptr;
615
0
    sal_uInt16 nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
616
0
    OUString sTopic, sItem, sReferer;
617
0
    LinkManager* pLinkMgr = pLink->GetLinkManager();
618
0
    if (pLinkMgr && sfx2::LinkManager::GetDisplayNames(pLink, nullptr, &sTopic, &sItem) && !sTopic.isEmpty())
619
0
    {
620
        // first only loop over the DocumentShells the shells and find those
621
        // with the name:
622
0
        CharClass aCC( LanguageTag( LANGUAGE_SYSTEM) );
623
624
0
        bool bFirst = true;
625
0
        SfxObjectShell* pShell = pLinkMgr->GetPersist();
626
0
        if( pShell && pShell->GetMedium() )
627
0
        {
628
0
            sReferer = pShell->GetMedium()->GetBaseURL();
629
0
            const SfxUInt16Item* pItem = pShell->GetMedium()->GetItemSet().GetItem(SID_UPDATEDOCMODE, false);
630
0
            if ( pItem )
631
0
                nUpdateMode = pItem->GetValue();
632
0
        }
633
634
0
        OUString sNmURL(aCC.lowercase(lcl_DDE_RelToAbs(sTopic, sReferer)));
635
636
0
        if ( !pShell )
637
0
        {
638
0
            bFirst = false;
639
0
            pShell = SfxObjectShell::GetFirst( nullptr, false );
640
0
        }
641
642
0
        OUString sTmp;
643
0
        while( pShell )
644
0
        {
645
0
            if( sTmp.isEmpty() )
646
0
            {
647
0
                sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
648
0
                sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
649
0
            }
650
651
652
0
            sTmp = aCC.lowercase( sTmp );
653
0
            if( sTmp == sNmURL )  // we want these
654
0
            {
655
0
                pFndShell = pShell;
656
0
                break;
657
0
            }
658
659
0
            if( bFirst )
660
0
            {
661
0
                bFirst = false;
662
0
                pShell = SfxObjectShell::GetFirst( nullptr, false );
663
0
            }
664
0
            else
665
0
                pShell = SfxObjectShell::GetNext( *pShell, nullptr, false );
666
667
0
            sTmp.clear();
668
0
        }
669
0
    }
670
671
    // empty topics are not allowed - which document is it
672
0
    if( sTopic.isEmpty() )
673
0
        return false;
674
675
0
    if (pFndShell)
676
0
    {
677
0
        sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
678
0
        if( pNewSrc )
679
0
        {
680
0
            css::datatransfer::DataFlavor aFl;
681
0
            SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
682
683
0
            pLink->SetObj( pNewSrc );
684
0
            pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
685
0
                                SfxLinkUpdateMode::ONCALL == pLink->GetUpdateMode()
686
0
                                    ? ADVISEMODE_ONLYONCE
687
0
                                    : 0 );
688
0
            return true;
689
0
        }
690
0
    }
691
0
    else
692
0
    {
693
        // then try to download the file:
694
0
        INetURLObject aURL( sTopic );
695
0
        INetProtocol eOld = aURL.GetProtocol();
696
0
        sTopic = lcl_DDE_RelToAbs( sTopic, sReferer );
697
0
        aURL.SetURL( sTopic );
698
0
        if( INetProtocol::NotValid != eOld ||
699
0
            INetProtocol::Http != aURL.GetProtocol() )
700
0
        {
701
0
            SfxStringItem aName( SID_FILE_NAME, sTopic );
702
0
            SfxBoolItem aMinimized(SID_MINIMIZED, true);
703
0
            SfxBoolItem aHidden(SID_HIDDEN, true);
704
0
            SfxStringItem aTarget( SID_TARGETNAME, u"_blank"_ustr );
705
0
            SfxStringItem aReferer( SID_REFERER, sReferer );
706
0
            SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
707
0
            SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
708
709
            // Disable automatic re-connection to avoid this link instance
710
            // being destroyed at re-connection.
711
0
            SfxBoolItem aDdeConnect(SID_DDE_RECONNECT_ONLOAD, false);
712
713
            // #i14200# (DDE-link crashes wordprocessor)
714
0
            SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
715
0
            aArgs.Put(aReferer);
716
0
            aArgs.Put(aTarget);
717
0
            aArgs.Put(aHidden);
718
0
            aArgs.Put(aMinimized);
719
0
            aArgs.Put(aName);
720
0
            aArgs.Put(aUpdate);
721
0
            aArgs.Put(aReadOnly);
722
0
            aArgs.Put(aDdeConnect);
723
0
            Reference<XComponent> xComp = SfxObjectShell::CreateAndLoadComponent(aArgs);
724
0
            pFndShell = SfxObjectShell::GetShellFromComponent(xComp);
725
0
            if (xComp.is() && pFndShell && pLinkMgr)
726
0
            {
727
0
                pLinkMgr->InsertCachedComp(xComp);
728
0
                sfx2::LinkManager::LinkServerShell(sItem, *pFndShell, *pLink);
729
0
                return true;
730
0
            }
731
0
        }
732
0
    }
733
734
0
    return false;
735
0
}
736
737
}
738
739
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */