1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include <com/sun/star/uno/Reference.h>
21 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/beans/NamedValue.hpp>
23 #include <com/sun/star/frame/FrameSearchFlag.hpp>
24 #include <com/sun/star/frame/XDispatchProvider.hpp>
25 #include <com/sun/star/frame/XFrame.hpp>
26 #include <com/sun/star/frame/Desktop.hpp>
27 #include <com/sun/star/util/URL.hpp>
28 #include <com/sun/star/util/URLTransformer.hpp>
29 #include <com/sun/star/util/XURLTransformer.hpp>
30 #include <com/sun/star/system/SystemShellExecuteException.hpp>
31 #include <com/sun/star/document/XTypeDetection.hpp>
32 #include <com/sun/star/document/MacroExecMode.hpp>
33 #include <com/sun/star/document/UpdateDocMode.hpp>
34 #include <com/sun/star/task/ErrorCodeRequest.hpp>
35 #include <com/sun/star/task/InteractionHandler.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/ElementModes.hpp>
38 #include <com/sun/star/embed/XStorage.hpp>
39 #include <com/sun/star/container/XNameAccess.hpp>
40 #include <com/sun/star/packages/WrongPasswordException.hpp>
41 #include <com/sun/star/uno/Sequence.h>
42 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <rtl/ustring.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/sequence.hxx>
48 #include <comphelper/storagehelper.hxx>
49 #include <comphelper/string.hxx>
50 #include <comphelper/synchronousdispatch.hxx>
52 #include <svl/intitem.hxx>
53 #include <svl/stritem.hxx>
54 #include <svl/eitem.hxx>
55 #include <sfx2/doctempl.hxx>
56 #include <svtools/sfxecode.hxx>
57 #include <preventduplicateinteraction.hxx>
58 #include <svtools/ehdl.hxx>
59 #include <unotools/pathoptions.hxx>
60 #include <unotools/securityoptions.hxx>
61 #include <unotools/moduleoptions.hxx>
62 #include <unotools/extendedsecurityoptions.hxx>
63 #include <comphelper/docpasswordhelper.hxx>
64 #include <vcl/svapp.hxx>
65 #include <vcl/weld.hxx>
67 #include <sfx2/app.hxx>
68 #include <sfx2/bindings.hxx>
69 #include <sfx2/dispatch.hxx>
70 #include <sfx2/docfile.hxx>
71 #include <sfx2/docfilt.hxx>
72 #include <sfx2/fcontnr.hxx>
73 #include <sfx2/objitem.hxx>
74 #include <sfx2/objsh.hxx>
75 #include <svl/slstitm.hxx>
76 #include <appopen.hxx>
77 #include <sfx2/request.hxx>
78 #include <sfx2/sfxresid.hxx>
79 #include <sfx2/viewsh.hxx>
80 #include <sfx2/strings.hrc>
81 #include <sfx2/viewfrm.hxx>
82 #include <sfx2/sfxuno.hxx>
83 #include <sfx2/objface.hxx>
84 #include <sfx2/filedlghelper.hxx>
85 #include <sfx2/templatedlg.hxx>
86 #include <sfx2/sfxsids.hrc>
87 #include <o3tl/string_view.hxx>
88 #include <openuriexternally.hxx>
90 #include <officecfg/Office/ProtocolHandler.hxx>
91 #include <officecfg/Office/Security.hxx>
93 using namespace ::com::sun::star
;
94 using namespace ::com::sun::star::beans
;
95 using namespace ::com::sun::star::frame
;
96 using namespace ::com::sun::star::lang
;
97 using namespace ::com::sun::star::uno
;
98 using namespace ::com::sun::star::util
;
99 using namespace ::com::sun::star::task
;
100 using namespace ::com::sun::star::container
;
101 using namespace ::cppu
;
102 using namespace ::sfx2
;
104 void SetTemplate_Impl( std::u16string_view rFileName
,
105 const OUString
&rLongName
,
106 SfxObjectShell
*pDoc
)
108 // write TemplateName to DocumentProperties of document
109 // TemplateDate stays as default (=current date)
110 pDoc
->ResetFromTemplate( rLongName
, rFileName
);
115 class SfxDocPasswordVerifier
: public ::comphelper::IDocPasswordVerifier
118 explicit SfxDocPasswordVerifier(SfxMedium
& rMedium
)
120 , mxStorage(rMedium
.GetStorage())
124 virtual ::comphelper::DocPasswordVerifierResult
125 verifyPassword( const OUString
& rPassword
, uno::Sequence
< beans::NamedValue
>& o_rEncryptionData
) override
;
126 virtual ::comphelper::DocPasswordVerifierResult
127 verifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
) override
;
130 SfxMedium
& m_rMedium
;
131 Reference
< embed::XStorage
> mxStorage
;
136 ::comphelper::DocPasswordVerifierResult
SfxDocPasswordVerifier::verifyPassword( const OUString
& rPassword
, uno::Sequence
< beans::NamedValue
>& o_rEncryptionData
)
138 o_rEncryptionData
= ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword
);
139 return verifyEncryptionData( o_rEncryptionData
);
143 ::comphelper::DocPasswordVerifierResult
SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
)
145 ::comphelper::DocPasswordVerifierResult eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
148 // check the encryption data
149 // if the data correct is the stream will be opened successfully
150 // and immediately closed
151 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage
, rEncryptionData
);
153 // for new ODF encryption, try to extract the encrypted inner package
154 // (it will become the SfxObjectShell storage)
155 if (!m_rMedium
.TryEncryptedInnerPackage(mxStorage
))
156 { // ... old ODF encryption:
157 mxStorage
->openStreamElement(
159 embed::ElementModes::READ
| embed::ElementModes::NOCREATE
);
162 // no exception -> success
163 eResult
= ::comphelper::DocPasswordVerifierResult::OK
;
165 catch( const packages::WrongPasswordException
& )
167 eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
169 catch( const uno::Exception
& )
171 // unknown error, report it as wrong password
172 // TODO/LATER: we need an additional way to report unknown problems in this case
173 eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
179 ErrCode CheckPasswd_Impl
181 SfxObjectShell
* pDoc
,
182 SfxMedium
* pFile
// the Medium and its Password should be obtained
187 Ask for the password for a medium, only works if it concerns storage.
188 If the password flag is set in the Document Info, then the password is
189 requested through a user dialogue and the set at the Set of the medium.
190 If the set does not exist the it is created.
193 ErrCode nRet
= ERRCODE_NONE
;
195 if( !pFile
->GetFilter() || pFile
->IsStorage() )
197 uno::Reference
< embed::XStorage
> xStorage
= pFile
->GetStorage();
200 uno::Reference
< beans::XPropertySet
> xStorageProps( xStorage
, uno::UNO_QUERY
);
201 if ( xStorageProps
.is() )
203 bool bIsEncrypted
= false;
204 uno::Sequence
< uno::Sequence
< beans::NamedValue
> > aGpgProperties
;
206 xStorageProps
->getPropertyValue(u
"HasEncryptedEntries"_ustr
)
208 xStorageProps
->getPropertyValue(u
"EncryptionGpGProperties"_ustr
)
210 } catch( uno::Exception
& )
213 // the storage either has no encrypted elements or it's just
214 // does not allow to detect it, probably it should be implemented later
219 css::uno::Reference
<css::awt::XWindow
> xWin(pDoc
? pDoc
->GetDialogParent(pFile
) : nullptr);
221 xWin
->setVisible(true);
223 nRet
= ERRCODE_SFX_CANTGETPASSWD
;
225 SfxItemSet
& rSet
= pFile
->GetItemSet();
226 Reference
< css::task::XInteractionHandler
> xInteractionHandler
= pFile
->GetInteractionHandler();
227 if( xInteractionHandler
.is() )
229 // use the comphelper password helper to request a password
231 const SfxStringItem
* pPasswordItem
= rSet
.GetItem(SID_PASSWORD
, false);
233 aPassword
= pPasswordItem
->GetValue();
235 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
236 const SfxUnoAnyItem
* pEncryptionDataItem
= rSet
.GetItem(SID_ENCRYPTIONDATA
, false);
237 if ( pEncryptionDataItem
)
238 pEncryptionDataItem
->GetValue() >>= aEncryptionData
;
240 // try if one of the public key entries is
241 // decryptable, then extract session key
243 if ( !aEncryptionData
.hasElements() && aGpgProperties
.hasElements() )
244 aEncryptionData
= ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties
);
246 // tdf#93389: if recovering a document, encryption data should contain
247 // entries for the real filter, not only for recovery ODF, to keep it
248 // encrypted. Pass this in encryption data.
249 // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
250 // to marshal this to requestAndVerifyDocPassword
251 if (rSet
.GetItemState(SID_DOC_SALVAGE
, false) == SfxItemState::SET
)
253 aEncryptionData
= comphelper::concatSequences(
254 aEncryptionData
, std::initializer_list
<beans::NamedValue
>{
255 { u
"ForSalvage"_ustr
, css::uno::Any(true) } });
258 SfxDocPasswordVerifier
aVerifier(*pFile
);
259 aEncryptionData
= ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
260 aVerifier
, aEncryptionData
, aPassword
, xInteractionHandler
, pFile
->GetOrigURL(), comphelper::DocPasswordRequestType::Standard
);
262 rSet
.ClearItem( SID_PASSWORD
);
263 rSet
.ClearItem( SID_ENCRYPTIONDATA
);
265 if ( aEncryptionData
.hasElements() )
267 rSet
.Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
271 // update the version list of the medium using the new password
272 pFile
->GetVersionList();
274 catch( uno::Exception
& )
276 // TODO/LATER: set the error code
282 nRet
= ERRCODE_IO_ABORT
;
288 OSL_FAIL( "A storage must implement XPropertySet interface!" );
289 nRet
= ERRCODE_SFX_CANTGETPASSWD
;
298 ErrCodeMsg
SfxApplication::LoadTemplate( SfxObjectShellLock
& xDoc
, const OUString
&rFileName
, std::unique_ptr
<SfxItemSet
> pSet
)
300 std::shared_ptr
<const SfxFilter
> pFilter
;
301 SfxMedium
aMedium( rFileName
, ( StreamMode::READ
| StreamMode::SHARE_DENYNONE
) );
303 if ( !aMedium
.GetStorage( false ).is() )
304 aMedium
.GetInStream();
306 if ( aMedium
.GetErrorIgnoreWarning() )
308 return aMedium
.GetErrorCode();
311 aMedium
.UseInteractionHandler( true );
312 ErrCode nErr
= GetFilterMatcher().GuessFilter( aMedium
, pFilter
, SfxFilterFlags::TEMPLATE
, SfxFilterFlags::NONE
);
313 if ( ERRCODE_NONE
!= nErr
)
315 return ERRCODE_SFX_NOTATEMPLATE
;
318 if( !pFilter
|| !pFilter
->IsAllowedAsTemplate() )
320 return ERRCODE_SFX_NOTATEMPLATE
;
323 if ( pFilter
->GetFilterFlags() & SfxFilterFlags::STARONEFILTER
)
325 DBG_ASSERT( !xDoc
.Is(), "Sorry, not implemented!" );
326 SfxStringItem
aName( SID_FILE_NAME
, rFileName
);
327 SfxStringItem
aReferer( SID_REFERER
, u
"private:user"_ustr
);
328 SfxStringItem
aFlags( SID_OPTIONS
, u
"T"_ustr
);
329 SfxBoolItem
aHidden( SID_HIDDEN
, true );
330 const SfxPoolItemHolder
aRet(GetDispatcher_Impl()->ExecuteList(
331 SID_OPENDOC
, SfxCallMode::SYNCHRON
,
332 { &aName
, &aHidden
, &aReferer
, &aFlags
} ));
333 const SfxObjectItem
* pObj(dynamic_cast<const SfxObjectItem
*>(aRet
.getItem()));
335 xDoc
= dynamic_cast<SfxObjectShell
*>( pObj
->GetShell() );
338 const SfxViewFrameItem
* pView(dynamic_cast<const SfxViewFrameItem
*>(aRet
.getItem()));
341 SfxViewFrame
*pFrame
= pView
->GetFrame();
343 xDoc
= pFrame
->GetObjectShell();
348 return ERRCODE_SFX_DOLOADFAILED
;
353 xDoc
= SfxObjectShell::CreateObject( pFilter
->GetServiceName() );
355 //pMedium takes ownership of pSet
356 SfxMedium
*pMedium
= new SfxMedium(rFileName
, StreamMode::STD_READ
, std::move(pFilter
), std::move(pSet
));
357 if(!xDoc
->DoLoad(pMedium
))
359 ErrCodeMsg nErrCode
= xDoc
->GetErrorCode();
368 // TODO: introduce error handling
370 uno::Reference
< embed::XStorage
> xTempStorage
= ::comphelper::OStorageHelper::GetTemporaryStorage();
371 if( !xTempStorage
.is() )
372 throw uno::RuntimeException();
374 xDoc
->GetStorage()->copyToStorage( xTempStorage
);
376 if ( !xDoc
->DoSaveCompleted( new SfxMedium( xTempStorage
, OUString() ) ) )
377 throw uno::RuntimeException();
379 catch( uno::Exception
& )
384 // TODO: transfer correct error outside
385 return ERRCODE_SFX_GENERAL
;
388 SetTemplate_Impl( rFileName
, OUString(), xDoc
);
391 xDoc
->InvalidateName();
392 xDoc
->SetModified(false);
395 css::uno::Reference
< css::frame::XModel
> xModel
= xDoc
->GetModel();
398 std::unique_ptr
<SfxItemSet
> pNew
= xDoc
->GetMedium()->GetItemSet().Clone();
399 pNew
->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL
);
400 pNew
->ClearItem( SID_FILTER_NAME
);
401 css::uno::Sequence
< css::beans::PropertyValue
> aArgs
;
402 TransformItems( SID_OPENDOC
, *pNew
, aArgs
);
403 sal_Int32 nLength
= aArgs
.getLength();
404 aArgs
.realloc( nLength
+ 1 );
405 auto pArgs
= aArgs
.getArray();
406 pArgs
[nLength
].Name
= "Title";
407 pArgs
[nLength
].Value
<<= xDoc
->GetTitle( SFX_TITLE_DETECT
);
408 xModel
->attachResource( OUString(), aArgs
);
411 return xDoc
->GetErrorCode();
415 void SfxApplication::NewDocDirectExec_Impl( SfxRequest
& rReq
)
417 const SfxStringItem
* pFactoryItem
= rReq
.GetArg
<SfxStringItem
>(SID_NEWDOCDIRECT
);
420 aFactName
= pFactoryItem
->GetValue();
422 aFactName
= SvtModuleOptions().GetDefaultModuleName();
424 SfxRequest
aReq( SID_OPENDOC
, SfxCallMode::SYNCHRON
, GetPool() );
425 aReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, "private:factory/" + aFactName
) );
426 aReq
.AppendItem( SfxFrameItem( SID_DOCFRAME
, GetFrame() ) );
427 aReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, u
"_default"_ustr
) );
429 // TODO/LATER: Should the other arguments be transferred as well?
430 const SfxStringItem
* pDefaultPathItem
= rReq
.GetArg
<SfxStringItem
>(SID_DEFAULTFILEPATH
);
431 if ( pDefaultPathItem
)
432 aReq
.AppendItem( *pDefaultPathItem
);
433 const SfxStringItem
* pDefaultNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_DEFAULTFILENAME
);
434 if ( pDefaultNameItem
)
435 aReq
.AppendItem( *pDefaultNameItem
);
437 SfxGetpApp()->ExecuteSlot( aReq
);
438 const SfxViewFrameItem
* pItem(dynamic_cast<const SfxViewFrameItem
*>(aReq
.GetReturnValue().getItem()));
439 if (nullptr != pItem
)
440 rReq
.SetReturnValue(SfxFrameItem(0, pItem
->GetFrame()));
443 void SfxApplication::NewDocDirectState_Impl( SfxItemSet
&rSet
)
445 rSet
.Put(SfxStringItem(SID_NEWDOCDIRECT
, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
448 void SfxApplication::NewDocExec_Impl( SfxRequest
& rReq
)
450 // No Parameter from BASIC only Factory given?
451 const SfxStringItem
* pTemplNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_TEMPLATE_NAME
);
452 const SfxStringItem
* pTemplFileNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
453 const SfxStringItem
* pTemplRegionNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_TEMPLATE_REGIONNAME
);
455 SfxObjectShellLock xDoc
;
457 OUString aTemplateRegion
, aTemplateName
, aTemplateFileName
;
458 bool bDirect
= false; // through FileName instead of Region/Template
459 SfxErrorContext
aEc(ERRCTX_SFX_NEWDOC
);
460 if ( !pTemplNameItem
&& !pTemplFileNameItem
)
462 bool bNewWin
= false;
463 weld::Window
* pTopWin
= GetTopWindow();
465 SfxObjectShell
* pCurrentShell
= SfxObjectShell::Current();
466 Reference
<XModel
> xModel
;
468 xModel
= pCurrentShell
->GetModel();
470 SfxTemplateManagerDlg
aTemplDlg(rReq
.GetFrameWeld());
473 aTemplDlg
.setDocumentModel(xModel
);
475 int nRet
= aTemplDlg
.run();
476 if ( nRet
== RET_OK
)
479 if ( pTopWin
!= GetTopWindow() )
481 // the dialogue opens a document -> a new TopWindow appears
482 pTopWin
= GetTopWindow();
487 if (bNewWin
&& pTopWin
)
489 // after the destruction of the dialogue its parent comes to top,
490 // but we want that the new document is on top
499 if ( pTemplNameItem
)
500 aTemplateName
= pTemplNameItem
->GetValue();
503 if ( pTemplRegionNameItem
)
504 aTemplateRegion
= pTemplRegionNameItem
->GetValue();
506 // Template-File-Name
507 if ( pTemplFileNameItem
)
509 aTemplateFileName
= pTemplFileNameItem
->GetValue();
514 ErrCode lErr
= ERRCODE_NONE
;
517 SfxDocumentTemplates aTmpFac
;
518 if( aTemplateFileName
.isEmpty() )
519 aTmpFac
.GetFull( aTemplateRegion
, aTemplateName
, aTemplateFileName
);
521 if( aTemplateFileName
.isEmpty() )
522 lErr
= ERRCODE_SFX_TEMPLATENOTFOUND
;
525 INetURLObject
aObj( aTemplateFileName
);
526 SfxErrorContext
aEC( ERRCTX_SFX_LOADTEMPLATE
, aObj
.PathToFileName() );
528 if ( lErr
!= ERRCODE_NONE
)
530 ErrCode lFatalErr
= lErr
.IgnoreWarning();
532 ErrorHandler::HandleError(lErr
);
536 SfxCallMode eMode
= SfxCallMode::SYNCHRON
;
537 SfxPoolItemHolder aResult
;
538 SfxStringItem
aReferer( SID_REFERER
, u
"private:user"_ustr
);
539 SfxStringItem
aTarget( SID_TARGETNAME
, u
"_default"_ustr
);
540 if ( !aTemplateFileName
.isEmpty() )
542 DBG_ASSERT( aObj
.GetProtocol() != INetProtocol::NotValid
, "Illegal URL!" );
544 SfxStringItem
aName( SID_FILE_NAME
, aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
545 SfxStringItem
aTemplName( SID_TEMPLATE_NAME
, aTemplateName
);
546 SfxStringItem
aTemplRegionName( SID_TEMPLATE_REGIONNAME
, aTemplateRegion
);
547 aResult
= GetDispatcher_Impl()->ExecuteList(SID_OPENDOC
, eMode
,
548 {&aName
, &aTarget
, &aReferer
, &aTemplName
, &aTemplRegionName
});
552 SfxStringItem
aName( SID_FILE_NAME
, u
"private:factory"_ustr
);
553 aResult
= GetDispatcher_Impl()->ExecuteList(SID_OPENDOC
, eMode
,
554 { &aName
, &aTarget
, &aReferer
} );
558 rReq
.SetReturnValue( *aResult
.getItem() );
566 * Check if a given filter type should open the hyperlinked document
569 * @param rFilter filter object
571 bool lcl_isFilterNativelySupported(const SfxFilter
& rFilter
)
573 if (rFilter
.IsOwnFormat())
576 const OUString
& aName
= rFilter
.GetFilterName();
577 // We can handle all Excel variants natively.
578 return aName
.startsWith("MS Excel");
583 void SfxApplication::OpenDocExec_Impl( SfxRequest
& rReq
)
585 OUString aDocService
;
586 const SfxStringItem
* pDocSrvItem
= rReq
.GetArg
<SfxStringItem
>(SID_DOC_SERVICE
);
588 aDocService
= pDocSrvItem
->GetValue();
590 sal_uInt16 nSID
= rReq
.GetSlot();
591 const SfxStringItem
* pFileNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
594 OUString
aCommand( pFileNameItem
->GetValue() );
595 const SfxSlot
* pSlot
= GetInterface()->GetSlot( aCommand
);
598 pFileNameItem
= nullptr;
602 if ( aCommand
.startsWith("slot:") )
604 sal_uInt16 nSlotId
= static_cast<sal_uInt16
>(o3tl::toInt32(aCommand
.subView(5)));
605 if ( nSlotId
== SID_OPENDOC
)
606 pFileNameItem
= nullptr;
611 if ( !pFileNameItem
)
613 // get FileName from dialog
614 std::vector
<OUString
> aURLList
;
616 std::optional
<SfxAllItemSet
> pSet
;
618 const SfxStringItem
* pFolderNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_PATH
);
619 if ( pFolderNameItem
)
620 aPath
= pFolderNameItem
->GetValue();
621 else if ( nSID
== SID_OPENTEMPLATE
)
623 aPath
= SvtPathOptions().GetTemplatePath();
624 if (!aPath
.isEmpty()) // if not empty then get last token
625 aPath
= aPath
.copy(aPath
.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
628 sal_Int16 nDialog
= SFX2_IMPL_DIALOG_CONFIG
;
629 const SfxBoolItem
* pSystemDialogItem
= rReq
.GetArg
<SfxBoolItem
>(SID_FILE_DIALOG
);
630 if ( pSystemDialogItem
)
631 nDialog
= pSystemDialogItem
->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM
: SFX2_IMPL_DIALOG_OOO
;
633 const SfxBoolItem
* pRemoteDialogItem
= rReq
.GetArg
<SfxBoolItem
>(SID_REMOTE_DIALOG
);
634 if ( pRemoteDialogItem
&& pRemoteDialogItem
->GetValue())
635 nDialog
= SFX2_IMPL_DIALOG_REMOTE
;
637 sal_Int16 nDialogType
= ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION
;
638 FileDialogFlags eDialogFlags
= FileDialogFlags::MultiSelection
;
639 const SfxBoolItem
* pSignPDFItem
= rReq
.GetArg
<SfxBoolItem
>(SID_SIGNPDF
);
640 if (pSignPDFItem
&& pSignPDFItem
->GetValue())
642 eDialogFlags
|= FileDialogFlags::SignPDF
;
643 nDialogType
= ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
;
646 OUString sStandardDir
;
648 const SfxStringItem
* pStandardDirItem
= rReq
.GetArg
<SfxStringItem
>(SID_STANDARD_DIR
);
649 if ( pStandardDirItem
)
650 sStandardDir
= pStandardDirItem
->GetValue();
652 css::uno::Sequence
< OUString
> aDenyList
;
654 const SfxStringListItem
* pDenyListItem
= rReq
.GetArg
<SfxStringListItem
>(SID_DENY_LIST
);
656 pDenyListItem
->GetStringList( aDenyList
);
658 weld::Window
* pTopWindow
= GetTopWindow();
659 ErrCode nErr
= sfx2::FileOpenDialog_Impl(pTopWindow
,
661 eDialogFlags
, aURLList
,
662 aFilter
, pSet
, &aPath
, nDialog
, sStandardDir
, aDenyList
);
664 if ( nErr
== ERRCODE_ABORT
)
670 rReq
.SetArgs( *pSet
);
671 if ( !aFilter
.isEmpty() )
672 rReq
.AppendItem( SfxStringItem( SID_FILTER_NAME
, aFilter
) );
673 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, u
"_default"_ustr
) );
674 rReq
.AppendItem( SfxStringItem( SID_REFERER
, u
"private:user"_ustr
) );
677 if(!aURLList
.empty())
679 if ( nSID
== SID_OPENTEMPLATE
)
680 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, false ) );
682 // This helper wraps an existing (or may new created InteractionHandler)
683 // intercept all incoming interactions and provide useful information
684 // later if the following transaction was finished.
686 rtl::Reference
<sfx2::PreventDuplicateInteraction
> pHandler
= new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
687 uno::Reference
<task::XInteractionHandler
> xHandler(pHandler
);
688 uno::Reference
<task::XInteractionHandler
> xWrappedHandler
;
690 // wrap existing handler or create new UUI handler
691 const SfxUnoAnyItem
* pInteractionItem
= rReq
.GetArg
<SfxUnoAnyItem
>(SID_INTERACTIONHANDLER
);
692 if (pInteractionItem
)
694 pInteractionItem
->GetValue() >>= xWrappedHandler
;
695 rReq
.RemoveItem( SID_INTERACTIONHANDLER
);
697 if (xWrappedHandler
.is())
698 pHandler
->setHandler(xWrappedHandler
);
700 pHandler
->useDefaultUUIHandler();
701 rReq
.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER
,css::uno::Any(xHandler
)) );
703 // define rules for this handler
704 css::uno::Type aInteraction
= ::cppu::UnoType
<css::task::ErrorCodeRequest
>::get();
705 ::sfx2::PreventDuplicateInteraction::InteractionInfo
aRule(aInteraction
);
706 pHandler
->addInteractionRule(aRule
);
708 if (!aDocService
.isEmpty())
710 rReq
.RemoveItem(SID_DOC_SERVICE
);
711 rReq
.AppendItem(SfxStringItem(SID_DOC_SERVICE
, aDocService
));
714 for (auto const& url
: aURLList
)
716 rReq
.RemoveItem( SID_FILE_NAME
);
717 rReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, url
) );
719 // Run synchronous, so that not the next document is loaded
721 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
722 // but only if reschedule is a problem
723 GetDispatcher_Impl()->Execute( SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs() );
725 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
726 // break loop then. Otherwise we risk showing the same interaction more than once.
727 if ( pHandler
->getInteractionInfo(aInteraction
, &aRule
) )
729 if (aRule
.m_nCallCount
> 0)
731 if (aRule
.m_xRequest
.is())
733 css::task::ErrorCodeRequest aRequest
;
734 if (aRule
.m_xRequest
->getRequest() >>= aRequest
)
736 if (aRequest
.ErrCode
== sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED
)))
750 bool bHyperlinkUsed
= false;
752 if ( SID_OPENURL
== nSID
)
754 // SID_OPENURL does the same as SID_OPENDOC!
755 rReq
.SetSlot( SID_OPENDOC
);
757 else if ( nSID
== SID_OPENTEMPLATE
)
759 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, false ) );
761 // pass URL to OS by using ShellExecuter or open it internal
762 // if it seems to be an own format.
764 There exist two possibilities to open hyperlinks:
765 a) using SID_OPENHYPERLINK (new)
766 b) using SID_BROWSE (old)
768 else if ( nSID
== SID_OPENHYPERLINK
)
770 rReq
.SetSlot( SID_OPENDOC
);
771 bHyperlinkUsed
= true;
774 // no else here! It's optional ...
777 const SfxBoolItem
* pHyperLinkUsedItem
= rReq
.GetArg
<SfxBoolItem
>(SID_BROWSE
);
778 if ( pHyperLinkUsedItem
)
779 bHyperlinkUsed
= pHyperLinkUsedItem
->GetValue();
780 // no "official" item, so remove it from ItemSet before using UNO-API
781 rReq
.RemoveItem( SID_BROWSE
);
784 const SfxStringItem
* pFileName
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
785 assert(pFileName
&& "SID_FILE_NAME is required");
786 OUString aFileName
= pFileName
->GetValue();
789 const SfxStringItem
* pRefererItem
= rReq
.GetArg
<SfxStringItem
>(SID_REFERER
);
791 aReferer
= pRefererItem
->GetValue();
793 const SfxStringItem
* pFileFlagsItem
= rReq
.GetArg
<SfxStringItem
>(SID_OPTIONS
);
794 if ( pFileFlagsItem
)
796 const OUString aFileFlags
= pFileFlagsItem
->GetValue().toAsciiUpperCase();
797 if ( aFileFlags
.indexOf('T') >= 0 )
799 rReq
.RemoveItem( SID_TEMPLATE
);
800 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, true ) );
803 if ( aFileFlags
.indexOf('H') >= 0 )
805 rReq
.RemoveItem( SID_HIDDEN
);
806 rReq
.AppendItem( SfxBoolItem( SID_HIDDEN
, true ) );
809 if ( aFileFlags
.indexOf('R') >= 0 )
811 rReq
.RemoveItem( SID_DOC_READONLY
);
812 rReq
.AppendItem( SfxBoolItem( SID_DOC_READONLY
, true ) );
815 if ( aFileFlags
.indexOf('B') >= 0 )
817 rReq
.RemoveItem( SID_PREVIEW
);
818 rReq
.AppendItem( SfxBoolItem( SID_PREVIEW
, true ) );
821 rReq
.RemoveItem( SID_OPTIONS
);
824 // Mark without URL cannot be handled by hyperlink code
825 if ( bHyperlinkUsed
&& !aFileName
.isEmpty() && aFileName
[0] != '#' )
827 uno::Reference
<document::XTypeDetection
> xTypeDetection(
828 comphelper::getProcessServiceFactory()->createInstance(u
"com.sun.star.document.TypeDetection"_ustr
), UNO_QUERY
);
830 if ( xTypeDetection
.is() )
834 aURL
.Complete
= aFileName
;
835 Reference
< util::XURLTransformer
> xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
836 xTrans
->parseStrict( aURL
);
838 INetProtocol aINetProtocol
= INetURLObject( aURL
.Complete
).GetProtocol();
839 auto eMode
= officecfg::Office::Security::Hyperlinks::Open::get();
841 if ( eMode
== SvtExtendedSecurityOptions::OPEN_NEVER
&& aINetProtocol
!= INetProtocol::VndSunStarHelp
)
843 SolarMutexGuard aGuard
;
844 weld::Window
*pWindow
= SfxGetpApp()->GetTopWindow();
846 std::unique_ptr
<weld::MessageDialog
> xSecurityWarningBox(Application::CreateMessageDialog(pWindow
,
847 VclMessageType::Warning
, VclButtonsType::Ok
, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS
)));
848 xSecurityWarningBox
->set_title(SfxResId(RID_SECURITY_WARNING_TITLE
));
849 xSecurityWarningBox
->run();
853 std::shared_ptr
<const SfxFilter
> pFilter
{};
855 // attempt loading native documents only if they are from a known protocol
856 // it might be sensible to limit the set of protocols even further, but that
857 // may cause regressions, needs further testing
858 // see tdf#136427 for details
859 if (aINetProtocol
!= INetProtocol::NotValid
) {
860 const OUString aTypeName
{ xTypeDetection
->queryTypeByURL( aURL
.Main
) };
861 SfxFilterMatcher
& rMatcher
= SfxGetpApp()->GetFilterMatcher();
862 pFilter
= rMatcher
.GetFilter4EA( aTypeName
);
865 bool bStartPresentation
= false;
868 const SfxUInt16Item
* pSlide
= rReq
.GetArg
<SfxUInt16Item
>(SID_DOC_STARTPRESENTATION
);
870 && (pFilter
->GetWildcard().Matches(u
".pptx")
871 || pFilter
->GetWildcard().Matches(u
".ppt")
872 || pFilter
->GetWildcard().Matches(u
".ppsx")
873 || pFilter
->GetWildcard().Matches(u
".pps")))
875 bStartPresentation
= true;
879 if (!pFilter
|| (!lcl_isFilterNativelySupported(*pFilter
) && !bStartPresentation
))
881 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
882 if ( aINetProtocol
== INetProtocol::Mailto
)
884 // don't dispatch mailto hyperlink to desktop dispatcher
885 rReq
.RemoveItem( SID_TARGETNAME
);
886 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, u
"_self"_ustr
) );
888 else if ( aINetProtocol
== INetProtocol::Ftp
||
889 aINetProtocol
== INetProtocol::Http
||
890 aINetProtocol
== INetProtocol::Https
)
892 sfx2::openUriExternally(aURL
.Complete
, true, rReq
.GetFrameWeld());
897 // check for "internal" protocols that should not be forwarded to the system
898 // add special protocols that always should be treated as internal
899 std::vector
< OUString
> aProtocols
{ u
"private:*"_ustr
, u
"vnd.sun.star.*"_ustr
};
901 // get registered protocol handlers from configuration
902 Reference
< XNameAccess
> xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
903 const Sequence
< OUString
> aNames
= xAccess
->getElementNames();
904 for ( const auto& rName
: aNames
)
906 Reference
< XPropertySet
> xSet
;
907 Any aRet
= xAccess
->getByName( rName
);
912 aRet
= xSet
->getPropertyValue(u
"Protocols"_ustr
);
913 Sequence
< OUString
> aTmp
;
916 aProtocols
.insert(aProtocols
.end(),std::cbegin(aTmp
),std::cend(aTmp
));
921 for (const OUString
& rProtocol
: aProtocols
)
923 WildCard
aPattern(rProtocol
);
924 if ( aPattern
.Matches( aURL
.Complete
) )
933 bool bLoadInternal
= false;
936 sfx2::openUriExternally(
937 aURL
.Complete
, pFilter
== nullptr, rReq
.GetFrameWeld());
939 catch ( css::system::SystemShellExecuteException
& )
941 rReq
.RemoveItem( SID_TARGETNAME
);
942 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, u
"_default"_ustr
) );
943 bLoadInternal
= true;
945 if ( !bLoadInternal
)
952 // hyperlink document must be loaded into a new frame
953 rReq
.RemoveItem( SID_TARGETNAME
);
954 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, u
"_default"_ustr
) );
959 if (!SvtSecurityOptions::isSecureMacroUri(aFileName
, aReferer
))
961 SfxErrorContext
aCtx( ERRCTX_SFX_OPENDOC
, aFileName
);
962 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED
);
966 SfxFrame
* pTargetFrame
= nullptr;
967 Reference
< XFrame
> xTargetFrame
;
969 const SfxFrameItem
* pFrameItem
= rReq
.GetArg
<SfxFrameItem
>(SID_DOCFRAME
);
971 pTargetFrame
= pFrameItem
->GetFrame();
975 const SfxUnoFrameItem
* pUnoFrameItem
= rReq
.GetArg
<SfxUnoFrameItem
>(SID_FILLFRAME
);
977 xTargetFrame
= pUnoFrameItem
->GetFrame();
980 if (!pTargetFrame
&& !xTargetFrame
.is())
982 if (const SfxViewFrame
* pViewFrame
= SfxViewFrame::Current())
983 pTargetFrame
= &pViewFrame
->GetFrame();
986 // check if caller has set a callback
987 std::unique_ptr
<SfxLinkItem
> pLinkItem
;
989 // remove from Itemset, because it confuses the parameter transformation
990 if (auto pParamLinkItem
= rReq
.GetArg
<SfxLinkItem
>(SID_DONELINK
))
991 pLinkItem
.reset(pParamLinkItem
->Clone());
993 rReq
.RemoveItem( SID_DONELINK
);
995 // check if the view must be hidden
996 bool bHidden
= false;
997 const SfxBoolItem
* pHidItem
= rReq
.GetArg
<SfxBoolItem
>(SID_HIDDEN
);
999 bHidden
= pHidItem
->GetValue();
1001 // This request is a UI call. We have to set the right values inside the MediaDescriptor
1002 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
1003 // But we have to look for already existing values or for real hidden requests.
1004 const SfxBoolItem
* pPreviewItem
= rReq
.GetArg
<SfxBoolItem
>(SID_PREVIEW
);
1005 if (!bHidden
&& ( !pPreviewItem
|| !pPreviewItem
->GetValue() ) )
1007 const SfxUnoAnyItem
* pInteractionItem
= rReq
.GetArg
<SfxUnoAnyItem
>(SID_INTERACTIONHANDLER
);
1008 const SfxUInt16Item
* pMacroExecItem
= rReq
.GetArg
<SfxUInt16Item
>(SID_MACROEXECMODE
);
1009 const SfxUInt16Item
* pDocTemplateItem
= rReq
.GetArg
<SfxUInt16Item
>(SID_UPDATEDOCMODE
);
1011 if (!pInteractionItem
)
1013 Reference
< task::XInteractionHandler2
> xHdl
= task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
1014 rReq
.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER
,css::uno::Any(xHdl
)) );
1016 if (!pMacroExecItem
)
1017 rReq
.AppendItem( SfxUInt16Item(SID_MACROEXECMODE
,css::document::MacroExecMode::USE_CONFIG
) );
1018 if (!pDocTemplateItem
)
1019 rReq
.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE
,css::document::UpdateDocMode::ACCORDING_TO_CONFIG
) );
1022 // extract target name
1024 const SfxStringItem
* pTargetItem
= rReq
.GetArg
<SfxStringItem
>(SID_TARGETNAME
);
1026 aTarget
= pTargetItem
->GetValue();
1029 const SfxBoolItem
* pNewViewItem
= rReq
.GetArg
<SfxBoolItem
>(SID_OPEN_NEW_VIEW
);
1030 if ( pNewViewItem
&& pNewViewItem
->GetValue() )
1031 aTarget
= "_blank" ;
1037 DBG_ASSERT( rReq
.IsSynchronCall() || pLinkItem
, "Hidden load process must be done synchronously!" );
1040 Reference
< XController
> xController
;
1041 // if a frame is given, it must be used for the starting point of the targeting mechanism
1042 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1043 if ( !xTargetFrame
.is() )
1047 xTargetFrame
= pTargetFrame
->GetFrameInterface();
1051 xTargetFrame
= Desktop::create(::comphelper::getProcessComponentContext());
1056 const SfxStringItem
* pURLItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
1057 aFileName
= pURLItem
->GetValue();
1058 if( aFileName
.startsWith("#") ) // Mark without URL
1060 SfxViewFrame
*pView
= pTargetFrame
? pTargetFrame
->GetCurrentViewFrame() : nullptr;
1062 pView
= SfxViewFrame::Current();
1064 pView
->GetViewShell()->JumpToMark( aFileName
.copy(1) );
1065 rReq
.SetReturnValue( SfxViewFrameItem( pView
) );
1069 // convert items to properties for framework API calls
1070 Sequence
< PropertyValue
> aArgs
;
1071 TransformItems( SID_OPENDOC
, *rReq
.GetArgs(), aArgs
);
1072 // Any Referer (that was relevant in the above call to
1073 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1074 // this "open" request is initiated directly by the user:
1075 auto pArg
= std::find_if(std::cbegin(aArgs
), std::cend(aArgs
),
1076 [](const PropertyValue
& rArg
) { return rArg
.Name
== "Referer"; });
1077 if (pArg
!= std::cend(aArgs
))
1079 auto nIndex
= static_cast<sal_Int32
>(std::distance(std::cbegin(aArgs
), pArg
));
1080 comphelper::removeElementAt(aArgs
, nIndex
);
1083 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1084 if( bHidden
|| pLinkItem
|| rReq
.IsSynchronCall() )
1086 // if loading must be done synchron, we must wait for completion to get a return value
1087 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1088 Reference
< XComponent
> xComp
;
1092 xComp
= ::comphelper::SynchronousDispatch::dispatch( xTargetFrame
, aFileName
, aTarget
, aArgs
);
1094 catch(const RuntimeException
&)
1098 catch(const css::uno::Exception
&)
1102 Reference
< XModel
> xModel( xComp
, UNO_QUERY
);
1104 xController
= xModel
->getCurrentController();
1106 xController
.set( xComp
, UNO_QUERY
);
1112 aURL
.Complete
= aFileName
;
1113 Reference
< util::XURLTransformer
> xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1114 xTrans
->parseStrict( aURL
);
1116 Reference
< XDispatchProvider
> xProv( xTargetFrame
, UNO_QUERY
);
1117 Reference
< XDispatch
> xDisp
= xProv
.is() ? xProv
->queryDispatch( aURL
, aTarget
, FrameSearchFlag::ALL
) : Reference
< XDispatch
>();
1119 xDisp
->dispatch( aURL
, aArgs
);
1122 if ( xController
.is() )
1124 // try to find the SfxFrame for the controller
1125 SfxFrame
* pCntrFrame
= nullptr;
1126 for ( SfxViewShell
* pShell
= SfxViewShell::GetFirst( false ); pShell
; pShell
= SfxViewShell::GetNext( *pShell
, false ) )
1128 if ( pShell
->GetController() == xController
)
1130 pCntrFrame
= &pShell
->GetViewFrame().GetFrame();
1137 SfxObjectShell
* pSh
= pCntrFrame
->GetCurrentDocument();
1138 DBG_ASSERT( pSh
, "Controller without ObjectShell ?!" );
1140 rReq
.SetReturnValue( SfxViewFrameItem( pCntrFrame
->GetCurrentViewFrame() ) );
1146 const SfxPoolItem
* pRetValue(rReq
.GetReturnValue().getItem());
1149 pLinkItem
->GetValue().Call(pRetValue
);
1154 void SfxApplication::OpenRemoteExec_Impl( SfxRequest
& rReq
)
1156 rReq
.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG
, true ) );
1157 GetDispatcher_Impl()->Execute( SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs() );
1160 void SfxApplication::SignPDFExec_Impl(SfxRequest
& rReq
)
1162 rReq
.AppendItem(SfxBoolItem(SID_SIGNPDF
, true));
1163 GetDispatcher_Impl()->Execute(SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs());
1166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */