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/synchronousdispatch.hxx>
51 #include <svl/intitem.hxx>
52 #include <svl/stritem.hxx>
53 #include <svl/eitem.hxx>
54 #include <sfx2/doctempl.hxx>
55 #include <svtools/sfxecode.hxx>
56 #include <preventduplicateinteraction.hxx>
57 #include <svtools/ehdl.hxx>
58 #include <unotools/pathoptions.hxx>
59 #include <unotools/securityoptions.hxx>
60 #include <unotools/moduleoptions.hxx>
61 #include <unotools/extendedsecurityoptions.hxx>
62 #include <comphelper/docpasswordhelper.hxx>
63 #include <vcl/svapp.hxx>
64 #include <vcl/weld.hxx>
66 #include <sfx2/app.hxx>
67 #include <sfx2/bindings.hxx>
68 #include <sfx2/dispatch.hxx>
69 #include <sfx2/docfile.hxx>
70 #include <sfx2/docfilt.hxx>
71 #include <sfx2/fcontnr.hxx>
72 #include <sfx2/objitem.hxx>
73 #include <sfx2/objsh.hxx>
74 #include <svl/slstitm.hxx>
75 #include <appopen.hxx>
76 #include <sfx2/request.hxx>
77 #include <sfx2/sfxresid.hxx>
78 #include <sfx2/viewsh.hxx>
79 #include <sfx2/strings.hrc>
80 #include <sfx2/viewfrm.hxx>
81 #include <sfx2/sfxuno.hxx>
82 #include <sfx2/objface.hxx>
83 #include <sfx2/filedlghelper.hxx>
84 #include <sfx2/templatedlg.hxx>
85 #include <sfx2/sfxsids.hrc>
86 #include <openuriexternally.hxx>
88 #include <officecfg/Office/ProtocolHandler.hxx>
89 #include <officecfg/Office/Security.hxx>
91 using namespace ::com::sun::star
;
92 using namespace ::com::sun::star::beans
;
93 using namespace ::com::sun::star::frame
;
94 using namespace ::com::sun::star::lang
;
95 using namespace ::com::sun::star::uno
;
96 using namespace ::com::sun::star::util
;
97 using namespace ::com::sun::star::task
;
98 using namespace ::com::sun::star::container
;
99 using namespace ::cppu
;
100 using namespace ::sfx2
;
102 void SetTemplate_Impl( const OUString
&rFileName
,
103 const OUString
&rLongName
,
104 SfxObjectShell
*pDoc
)
106 // write TemplateName to DocumentProperties of document
107 // TemplateDate stays as default (=current date)
108 pDoc
->ResetFromTemplate( rLongName
, rFileName
);
113 class SfxDocPasswordVerifier
: public ::comphelper::IDocPasswordVerifier
116 explicit SfxDocPasswordVerifier( const Reference
< embed::XStorage
>& rxStorage
) :
117 mxStorage( rxStorage
) {}
119 virtual ::comphelper::DocPasswordVerifierResult
120 verifyPassword( const OUString
& rPassword
, uno::Sequence
< beans::NamedValue
>& o_rEncryptionData
) override
;
121 virtual ::comphelper::DocPasswordVerifierResult
122 verifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
) override
;
126 Reference
< embed::XStorage
> mxStorage
;
131 ::comphelper::DocPasswordVerifierResult
SfxDocPasswordVerifier::verifyPassword( const OUString
& rPassword
, uno::Sequence
< beans::NamedValue
>& o_rEncryptionData
)
133 o_rEncryptionData
= ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword
);
134 return verifyEncryptionData( o_rEncryptionData
);
138 ::comphelper::DocPasswordVerifierResult
SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
)
140 ::comphelper::DocPasswordVerifierResult eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
143 // check the encryption data
144 // if the data correct is the stream will be opened successfully
145 // and immediately closed
146 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage
, rEncryptionData
);
148 mxStorage
->openStreamElement(
150 embed::ElementModes::READ
| embed::ElementModes::NOCREATE
);
152 // no exception -> success
153 eResult
= ::comphelper::DocPasswordVerifierResult::OK
;
155 catch( const packages::WrongPasswordException
& )
157 eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
159 catch( const uno::Exception
& )
161 // unknown error, report it as wrong password
162 // TODO/LATER: we need an additional way to report unknown problems in this case
163 eResult
= ::comphelper::DocPasswordVerifierResult::WrongPassword
;
169 ErrCode CheckPasswd_Impl
171 SfxObjectShell
* pDoc
,
172 SfxMedium
* pFile
// the Medium and its Password should be obtained
177 Ask for the password for a medium, only works if it concerns storage.
178 If the password flag is set in the Document Info, then the password is
179 requested through a user dialogue and the set at the Set of the medium.
180 If the set does not exist the it is created.
183 ErrCode nRet
= ERRCODE_NONE
;
185 if( !pFile
->GetFilter() || pFile
->IsStorage() )
187 uno::Reference
< embed::XStorage
> xStorage
= pFile
->GetStorage();
190 uno::Reference
< beans::XPropertySet
> xStorageProps( xStorage
, uno::UNO_QUERY
);
191 if ( xStorageProps
.is() )
193 bool bIsEncrypted
= false;
194 uno::Sequence
< uno::Sequence
< beans::NamedValue
> > aGpgProperties
;
196 xStorageProps
->getPropertyValue("HasEncryptedEntries")
198 xStorageProps
->getPropertyValue("EncryptionGpGProperties")
200 } catch( uno::Exception
& )
203 // the storage either has no encrypted elements or it's just
204 // does not allow to detect it, probably it should be implemented later
209 vcl::Window
* pWin
= pDoc
? pDoc
->GetDialogParent( pFile
) : nullptr;
213 nRet
= ERRCODE_SFX_CANTGETPASSWD
;
215 SfxItemSet
*pSet
= pFile
->GetItemSet();
218 Reference
< css::task::XInteractionHandler
> xInteractionHandler
= pFile
->GetInteractionHandler();
219 if( xInteractionHandler
.is() )
221 // use the comphelper password helper to request a password
223 const SfxStringItem
* pPasswordItem
= SfxItemSet::GetItem
<SfxStringItem
>(pSet
, SID_PASSWORD
, false);
225 aPassword
= pPasswordItem
->GetValue();
227 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
228 const SfxUnoAnyItem
* pEncryptionDataItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(pSet
, SID_ENCRYPTIONDATA
, false);
229 if ( pEncryptionDataItem
)
230 pEncryptionDataItem
->GetValue() >>= aEncryptionData
;
232 // try if one of the public key entries is
233 // decryptable, then extract session key
235 if ( !aEncryptionData
.hasElements() && aGpgProperties
.hasElements() )
236 aEncryptionData
= ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties
);
238 // tdf#93389: if recovering a document, encryption data should contain
239 // entries for the real filter, not only for recovery ODF, to keep it
240 // encrypted. Pass this in encryption data.
241 // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
242 // to marshal this to requestAndVerifyDocPassword
243 if (pSet
->GetItemState(SID_DOC_SALVAGE
, false) == SfxItemState::SET
)
245 aEncryptionData
= comphelper::concatSequences(
246 aEncryptionData
, std::initializer_list
<beans::NamedValue
>{
247 { "ForSalvage", css::uno::Any(true) } });
250 SfxDocPasswordVerifier
aVerifier( xStorage
);
251 aEncryptionData
= ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
252 aVerifier
, aEncryptionData
, aPassword
, xInteractionHandler
, pFile
->GetOrigURL(), comphelper::DocPasswordRequestType::Standard
);
254 pSet
->ClearItem( SID_PASSWORD
);
255 pSet
->ClearItem( SID_ENCRYPTIONDATA
);
257 if ( aEncryptionData
.hasElements() )
259 pSet
->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
263 // update the version list of the medium using the new password
264 pFile
->GetVersionList();
266 catch( uno::Exception
& )
268 // TODO/LATER: set the error code
274 nRet
= ERRCODE_IO_ABORT
;
281 OSL_FAIL( "A storage must implement XPropertySet interface!" );
282 nRet
= ERRCODE_SFX_CANTGETPASSWD
;
291 ErrCode
SfxApplication::LoadTemplate( SfxObjectShellLock
& xDoc
, const OUString
&rFileName
, std::unique_ptr
<SfxItemSet
> pSet
)
293 std::shared_ptr
<const SfxFilter
> pFilter
;
294 SfxMedium
aMedium( rFileName
, ( StreamMode::READ
| StreamMode::SHARE_DENYNONE
) );
296 if ( !aMedium
.GetStorage( false ).is() )
297 aMedium
.GetInStream();
299 if ( aMedium
.GetError() )
301 return aMedium
.GetErrorCode();
304 aMedium
.UseInteractionHandler( true );
305 ErrCode nErr
= GetFilterMatcher().GuessFilter( aMedium
, pFilter
, SfxFilterFlags::TEMPLATE
, SfxFilterFlags::NONE
);
306 if ( ERRCODE_NONE
!= nErr
)
308 return ERRCODE_SFX_NOTATEMPLATE
;
311 if( !pFilter
|| !pFilter
->IsAllowedAsTemplate() )
313 return ERRCODE_SFX_NOTATEMPLATE
;
316 if ( pFilter
->GetFilterFlags() & SfxFilterFlags::STARONEFILTER
)
318 DBG_ASSERT( !xDoc
.Is(), "Sorry, not implemented!" );
319 SfxStringItem
aName( SID_FILE_NAME
, rFileName
);
320 SfxStringItem
aReferer( SID_REFERER
, "private:user" );
321 SfxStringItem
aFlags( SID_OPTIONS
, "T" );
322 SfxBoolItem
aHidden( SID_HIDDEN
, true );
323 const SfxPoolItem
*pRet
= GetDispatcher_Impl()->ExecuteList(
324 SID_OPENDOC
, SfxCallMode::SYNCHRON
,
325 { &aName
, &aHidden
, &aReferer
, &aFlags
} );
326 const SfxObjectItem
*pObj
= dynamic_cast<const SfxObjectItem
*>( pRet
);
328 xDoc
= dynamic_cast<SfxObjectShell
*>( pObj
->GetShell() );
331 const SfxViewFrameItem
*pView
= dynamic_cast<const SfxViewFrameItem
*>( pRet
);
334 SfxViewFrame
*pFrame
= pView
->GetFrame();
336 xDoc
= pFrame
->GetObjectShell();
341 return ERRCODE_SFX_DOLOADFAILED
;
346 xDoc
= SfxObjectShell::CreateObject( pFilter
->GetServiceName() );
348 //pMedium takes ownership of pSet
349 SfxMedium
*pMedium
= new SfxMedium( rFileName
, StreamMode::STD_READ
, pFilter
, std::move(pSet
) );
350 if(!xDoc
->DoLoad(pMedium
))
352 ErrCode nErrCode
= xDoc
->GetErrorCode();
361 // TODO: introduce error handling
363 uno::Reference
< embed::XStorage
> xTempStorage
= ::comphelper::OStorageHelper::GetTemporaryStorage();
364 if( !xTempStorage
.is() )
365 throw uno::RuntimeException();
367 xDoc
->GetStorage()->copyToStorage( xTempStorage
);
369 if ( !xDoc
->DoSaveCompleted( new SfxMedium( xTempStorage
, OUString() ) ) )
370 throw uno::RuntimeException();
372 catch( uno::Exception
& )
377 // TODO: transfer correct error outside
378 return ERRCODE_SFX_GENERAL
;
381 SetTemplate_Impl( rFileName
, OUString(), xDoc
);
384 xDoc
->InvalidateName();
385 xDoc
->SetModified(false);
388 css::uno::Reference
< css::frame::XModel
> xModel
= xDoc
->GetModel();
391 std::unique_ptr
<SfxItemSet
> pNew
= xDoc
->GetMedium()->GetItemSet()->Clone();
392 pNew
->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL
);
393 pNew
->ClearItem( SID_FILTER_NAME
);
394 css::uno::Sequence
< css::beans::PropertyValue
> aArgs
;
395 TransformItems( SID_OPENDOC
, *pNew
, aArgs
);
396 sal_Int32 nLength
= aArgs
.getLength();
397 aArgs
.realloc( nLength
+ 1 );
398 aArgs
[nLength
].Name
= "Title";
399 aArgs
[nLength
].Value
<<= xDoc
->GetTitle( SFX_TITLE_DETECT
);
400 xModel
->attachResource( OUString(), aArgs
);
403 return xDoc
->GetErrorCode();
407 void SfxApplication::NewDocDirectExec_Impl( SfxRequest
& rReq
)
409 const SfxStringItem
* pFactoryItem
= rReq
.GetArg
<SfxStringItem
>(SID_NEWDOCDIRECT
);
412 aFactName
= pFactoryItem
->GetValue();
414 aFactName
= SvtModuleOptions().GetDefaultModuleName();
416 SfxRequest
aReq( SID_OPENDOC
, SfxCallMode::SYNCHRON
, GetPool() );
417 aReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, "private:factory/" + aFactName
) );
418 aReq
.AppendItem( SfxFrameItem( SID_DOCFRAME
, GetFrame() ) );
419 aReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_default" ) );
421 // TODO/LATER: Should the other arguments be transferred as well?
422 const SfxStringItem
* pDefaultPathItem
= rReq
.GetArg
<SfxStringItem
>(SID_DEFAULTFILEPATH
);
423 if ( pDefaultPathItem
)
424 aReq
.AppendItem( *pDefaultPathItem
);
425 const SfxStringItem
* pDefaultNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_DEFAULTFILENAME
);
426 if ( pDefaultNameItem
)
427 aReq
.AppendItem( *pDefaultNameItem
);
429 SfxGetpApp()->ExecuteSlot( aReq
);
430 const SfxViewFrameItem
* pItem
= dynamic_cast<const SfxViewFrameItem
*>( aReq
.GetReturnValue() );
432 rReq
.SetReturnValue( SfxFrameItem( 0, pItem
->GetFrame() ) );
435 void SfxApplication::NewDocDirectState_Impl( SfxItemSet
&rSet
)
437 rSet
.Put(SfxStringItem(SID_NEWDOCDIRECT
, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
440 void SfxApplication::NewDocExec_Impl( SfxRequest
& rReq
)
442 // No Parameter from BASIC only Factory given?
443 const SfxStringItem
* pTemplNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_TEMPLATE_NAME
);
444 const SfxStringItem
* pTemplFileNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
445 const SfxStringItem
* pTemplRegionNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_TEMPLATE_REGIONNAME
);
447 SfxObjectShellLock xDoc
;
449 OUString aTemplateRegion
, aTemplateName
, aTemplateFileName
;
450 bool bDirect
= false; // through FileName instead of Region/Template
451 SfxErrorContext
aEc(ERRCTX_SFX_NEWDOC
);
452 if ( !pTemplNameItem
&& !pTemplFileNameItem
)
454 bool bNewWin
= false;
455 vcl::Window
* pTopWin
= GetTopWindow();
457 SfxObjectShell
* pCurrentShell
= SfxObjectShell::Current();
458 Reference
<XModel
> xModel
;
460 xModel
= pCurrentShell
->GetModel();
462 SfxTemplateManagerDlg
aTemplDlg(rReq
.GetFrameWeld());
465 aTemplDlg
.setDocumentModel(xModel
);
467 int nRet
= aTemplDlg
.run();
468 if ( nRet
== RET_OK
)
471 if ( pTopWin
!= GetTopWindow() )
473 // the dialogue opens a document -> a new TopWindow appears
474 pTopWin
= GetTopWindow();
479 if ( bNewWin
&& pTopWin
)
480 // after the destruction of the dialogue its parent comes to top,
481 // but we want that the new document is on top
489 if ( pTemplNameItem
)
490 aTemplateName
= pTemplNameItem
->GetValue();
493 if ( pTemplRegionNameItem
)
494 aTemplateRegion
= pTemplRegionNameItem
->GetValue();
496 // Template-File-Name
497 if ( pTemplFileNameItem
)
499 aTemplateFileName
= pTemplFileNameItem
->GetValue();
504 ErrCode lErr
= ERRCODE_NONE
;
505 SfxItemSet
* pSet
= new SfxAllItemSet( GetPool() );
506 pSet
->Put( SfxBoolItem( SID_TEMPLATE
, true ) );
509 SfxDocumentTemplates aTmpFac
;
510 if( aTemplateFileName
.isEmpty() )
511 aTmpFac
.GetFull( aTemplateRegion
, aTemplateName
, aTemplateFileName
);
513 if( aTemplateFileName
.isEmpty() )
514 lErr
= ERRCODE_SFX_TEMPLATENOTFOUND
;
517 INetURLObject
aObj( aTemplateFileName
);
518 SfxErrorContext
aEC( ERRCTX_SFX_LOADTEMPLATE
, aObj
.PathToFileName() );
520 if ( lErr
!= ERRCODE_NONE
)
522 ErrCode lFatalErr
= lErr
.IgnoreWarning();
524 ErrorHandler::HandleError(lErr
);
528 SfxCallMode eMode
= SfxCallMode::SYNCHRON
;
530 const SfxPoolItem
*pRet
=nullptr;
531 SfxStringItem
aReferer( SID_REFERER
, "private:user" );
532 SfxStringItem
aTarget( SID_TARGETNAME
, "_default" );
533 if ( !aTemplateFileName
.isEmpty() )
535 DBG_ASSERT( aObj
.GetProtocol() != INetProtocol::NotValid
, "Illegal URL!" );
537 SfxStringItem
aName( SID_FILE_NAME
, aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
538 SfxStringItem
aTemplName( SID_TEMPLATE_NAME
, aTemplateName
);
539 SfxStringItem
aTemplRegionName( SID_TEMPLATE_REGIONNAME
, aTemplateRegion
);
540 pRet
= GetDispatcher_Impl()->ExecuteList(SID_OPENDOC
, eMode
,
541 {&aName
, &aTarget
, &aReferer
, &aTemplName
, &aTemplRegionName
});
545 SfxStringItem
aName( SID_FILE_NAME
, "private:factory" );
546 pRet
= GetDispatcher_Impl()->ExecuteList(SID_OPENDOC
, eMode
,
547 { &aName
, &aTarget
, &aReferer
} );
551 rReq
.SetReturnValue( *pRet
);
559 * Check if a given filter type should open the hyperlinked document
562 * @param rFilter filter object
564 bool lcl_isFilterNativelySupported(const SfxFilter
& rFilter
)
566 if (rFilter
.IsOwnFormat())
569 const OUString
& aName
= rFilter
.GetFilterName();
570 // We can handle all Excel variants natively.
571 return aName
.startsWith("MS Excel");
576 void SfxApplication::OpenDocExec_Impl( SfxRequest
& rReq
)
578 OUString aDocService
;
579 const SfxStringItem
* pDocSrvItem
= rReq
.GetArg
<SfxStringItem
>(SID_DOC_SERVICE
);
581 aDocService
= pDocSrvItem
->GetValue();
583 sal_uInt16 nSID
= rReq
.GetSlot();
584 const SfxStringItem
* pFileNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
587 OUString
aCommand( pFileNameItem
->GetValue() );
588 const SfxSlot
* pSlot
= GetInterface()->GetSlot( aCommand
);
591 pFileNameItem
= nullptr;
595 if ( aCommand
.startsWith("slot:") )
597 sal_uInt16 nSlotId
= static_cast<sal_uInt16
>(aCommand
.copy(5).toInt32());
598 if ( nSlotId
== SID_OPENDOC
)
599 pFileNameItem
= nullptr;
604 if ( !pFileNameItem
)
606 // get FileName from dialog
607 std::vector
<OUString
> aURLList
;
609 std::unique_ptr
<SfxItemSet
> pSet
;
611 const SfxStringItem
* pFolderNameItem
= rReq
.GetArg
<SfxStringItem
>(SID_PATH
);
612 if ( pFolderNameItem
)
613 aPath
= pFolderNameItem
->GetValue();
614 else if ( nSID
== SID_OPENTEMPLATE
)
616 aPath
= SvtPathOptions().GetTemplatePath();
617 if (!aPath
.isEmpty()) // if not empty then get last token
618 aPath
= aPath
.copy(aPath
.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
621 sal_Int16 nDialog
= SFX2_IMPL_DIALOG_CONFIG
;
622 const SfxBoolItem
* pSystemDialogItem
= rReq
.GetArg
<SfxBoolItem
>(SID_FILE_DIALOG
);
623 if ( pSystemDialogItem
)
624 nDialog
= pSystemDialogItem
->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM
: SFX2_IMPL_DIALOG_OOO
;
626 const SfxBoolItem
* pRemoteDialogItem
= rReq
.GetArg
<SfxBoolItem
>(SID_REMOTE_DIALOG
);
627 if ( pRemoteDialogItem
&& pRemoteDialogItem
->GetValue())
628 nDialog
= SFX2_IMPL_DIALOG_REMOTE
;
630 sal_Int16 nDialogType
= ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION
;
631 FileDialogFlags eDialogFlags
= FileDialogFlags::MultiSelection
;
632 const SfxBoolItem
* pSignPDFItem
= rReq
.GetArg
<SfxBoolItem
>(SID_SIGNPDF
);
633 if (pSignPDFItem
&& pSignPDFItem
->GetValue())
635 eDialogFlags
|= FileDialogFlags::SignPDF
;
636 nDialogType
= ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
;
639 OUString sStandardDir
;
641 const SfxStringItem
* pStandardDirItem
= rReq
.GetArg
<SfxStringItem
>(SID_STANDARD_DIR
);
642 if ( pStandardDirItem
)
643 sStandardDir
= pStandardDirItem
->GetValue();
645 css::uno::Sequence
< OUString
> aDenyList
;
647 const SfxStringListItem
* pDenyListItem
= rReq
.GetArg
<SfxStringListItem
>(SID_DENY_LIST
);
649 pDenyListItem
->GetStringList( aDenyList
);
651 vcl::Window
* pTopWindow
= GetTopWindow();
652 ErrCode nErr
= sfx2::FileOpenDialog_Impl(pTopWindow
? pTopWindow
->GetFrameWeld() : nullptr,
654 eDialogFlags
, aURLList
,
655 aFilter
, pSet
, &aPath
, nDialog
, sStandardDir
, aDenyList
);
657 if ( nErr
== ERRCODE_ABORT
)
663 rReq
.SetArgs( *static_cast<SfxAllItemSet
*>(pSet
.get()) );
664 if ( !aFilter
.isEmpty() )
665 rReq
.AppendItem( SfxStringItem( SID_FILTER_NAME
, aFilter
) );
666 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_default" ) );
667 rReq
.AppendItem( SfxStringItem( SID_REFERER
, "private:user" ) );
670 if(!aURLList
.empty())
672 if ( nSID
== SID_OPENTEMPLATE
)
673 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, false ) );
675 // This helper wraps an existing (or may new created InteractionHandler)
676 // intercept all incoming interactions and provide useful information
677 // later if the following transaction was finished.
679 sfx2::PreventDuplicateInteraction
* pHandler
= new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
680 uno::Reference
<task::XInteractionHandler
> xHandler(static_cast< css::task::XInteractionHandler
* >(pHandler
), css::uno::UNO_QUERY
);
681 uno::Reference
<task::XInteractionHandler
> xWrappedHandler
;
683 // wrap existing handler or create new UUI handler
684 const SfxUnoAnyItem
* pInteractionItem
= rReq
.GetArg
<SfxUnoAnyItem
>(SID_INTERACTIONHANDLER
);
685 if (pInteractionItem
)
687 pInteractionItem
->GetValue() >>= xWrappedHandler
;
688 rReq
.RemoveItem( SID_INTERACTIONHANDLER
);
690 if (xWrappedHandler
.is())
691 pHandler
->setHandler(xWrappedHandler
);
693 pHandler
->useDefaultUUIHandler();
694 rReq
.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER
,css::uno::makeAny(xHandler
)) );
696 // define rules for this handler
697 css::uno::Type aInteraction
= ::cppu::UnoType
<css::task::ErrorCodeRequest
>::get();
698 ::sfx2::PreventDuplicateInteraction::InteractionInfo
aRule(aInteraction
);
699 pHandler
->addInteractionRule(aRule
);
701 if (!aDocService
.isEmpty())
703 rReq
.RemoveItem(SID_DOC_SERVICE
);
704 rReq
.AppendItem(SfxStringItem(SID_DOC_SERVICE
, aDocService
));
707 for (auto const& url
: aURLList
)
709 rReq
.RemoveItem( SID_FILE_NAME
);
710 rReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, url
) );
712 // Run synchronous, so that not the next document is loaded
714 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
715 // but only if reschedule is a problem
716 GetDispatcher_Impl()->Execute( SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs() );
718 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
719 // break loop then. Otherwise we risk showing the same interaction more than once.
720 if ( pHandler
->getInteractionInfo(aInteraction
, &aRule
) )
722 if (aRule
.m_nCallCount
> 0)
724 if (aRule
.m_xRequest
.is())
726 css::task::ErrorCodeRequest aRequest
;
727 if (aRule
.m_xRequest
->getRequest() >>= aRequest
)
729 if (aRequest
.ErrCode
== sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED
)))
743 bool bHyperlinkUsed
= false;
745 if ( SID_OPENURL
== nSID
)
747 // SID_OPENURL does the same as SID_OPENDOC!
748 rReq
.SetSlot( SID_OPENDOC
);
750 else if ( nSID
== SID_OPENTEMPLATE
)
752 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, false ) );
754 // pass URL to OS by using ShellExecuter or open it internal
755 // if it seems to be an own format.
757 There exist two possibilities to open hyperlinks:
758 a) using SID_OPENHYPERLINK (new)
759 b) using SID_BROWSE (old)
761 else if ( nSID
== SID_OPENHYPERLINK
)
763 rReq
.SetSlot( SID_OPENDOC
);
764 bHyperlinkUsed
= true;
767 // no else here! It's optional ...
770 const SfxBoolItem
* pHyperLinkUsedItem
= rReq
.GetArg
<SfxBoolItem
>(SID_BROWSE
);
771 if ( pHyperLinkUsedItem
)
772 bHyperlinkUsed
= pHyperLinkUsedItem
->GetValue();
773 // no "official" item, so remove it from ItemSet before using UNO-API
774 rReq
.RemoveItem( SID_BROWSE
);
777 const SfxStringItem
* pFileName
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
778 OUString aFileName
= pFileName
->GetValue();
781 const SfxStringItem
* pRefererItem
= rReq
.GetArg
<SfxStringItem
>(SID_REFERER
);
783 aReferer
= pRefererItem
->GetValue();
785 const SfxStringItem
* pFileFlagsItem
= rReq
.GetArg
<SfxStringItem
>(SID_OPTIONS
);
786 if ( pFileFlagsItem
)
788 const OUString aFileFlags
= pFileFlagsItem
->GetValue().toAsciiUpperCase();
789 if ( aFileFlags
.indexOf('T') >= 0 )
791 rReq
.RemoveItem( SID_TEMPLATE
);
792 rReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, true ) );
795 if ( aFileFlags
.indexOf('H') >= 0 )
797 rReq
.RemoveItem( SID_HIDDEN
);
798 rReq
.AppendItem( SfxBoolItem( SID_HIDDEN
, true ) );
801 if ( aFileFlags
.indexOf('R') >= 0 )
803 rReq
.RemoveItem( SID_DOC_READONLY
);
804 rReq
.AppendItem( SfxBoolItem( SID_DOC_READONLY
, true ) );
807 if ( aFileFlags
.indexOf('B') >= 0 )
809 rReq
.RemoveItem( SID_PREVIEW
);
810 rReq
.AppendItem( SfxBoolItem( SID_PREVIEW
, true ) );
813 rReq
.RemoveItem( SID_OPTIONS
);
816 // Mark without URL cannot be handled by hyperlink code
817 if ( bHyperlinkUsed
&& !aFileName
.isEmpty() && aFileName
[0] != '#' )
819 uno::Reference
<document::XTypeDetection
> xTypeDetection(
820 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY
);
822 if ( xTypeDetection
.is() )
826 aURL
.Complete
= aFileName
;
827 Reference
< util::XURLTransformer
> xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
828 xTrans
->parseStrict( aURL
);
830 INetProtocol aINetProtocol
= INetURLObject( aURL
.Complete
).GetProtocol();
831 auto eMode
= officecfg::Office::Security::Hyperlinks::Open::get();
833 if ( eMode
== SvtExtendedSecurityOptions::OPEN_NEVER
&& aINetProtocol
!= INetProtocol::VndSunStarHelp
)
835 SolarMutexGuard aGuard
;
836 vcl::Window
*pWindow
= SfxGetpApp()->GetTopWindow();
838 std::unique_ptr
<weld::MessageDialog
> xSecurityWarningBox(Application::CreateMessageDialog(pWindow
? pWindow
->GetFrameWeld() : nullptr,
839 VclMessageType::Warning
, VclButtonsType::Ok
, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS
)));
840 xSecurityWarningBox
->set_title(SfxResId(RID_SECURITY_WARNING_TITLE
));
841 xSecurityWarningBox
->run();
845 const OUString aTypeName
{ xTypeDetection
->queryTypeByURL( aURL
.Main
) };
846 SfxFilterMatcher
& rMatcher
= SfxGetpApp()->GetFilterMatcher();
847 std::shared_ptr
<const SfxFilter
> pFilter
= rMatcher
.GetFilter4EA( aTypeName
);
848 if (!pFilter
|| !lcl_isFilterNativelySupported(*pFilter
))
850 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
851 if ( aINetProtocol
== INetProtocol::Mailto
)
853 // don't dispatch mailto hyperlink to desktop dispatcher
854 rReq
.RemoveItem( SID_TARGETNAME
);
855 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_self" ) );
857 else if ( aINetProtocol
== INetProtocol::Ftp
||
858 aINetProtocol
== INetProtocol::Http
||
859 aINetProtocol
== INetProtocol::Https
)
861 sfx2::openUriExternally(aURL
.Complete
, true);
866 // check for "internal" protocols that should not be forwarded to the system
867 std::vector
< OUString
> aProtocols(2);
869 // add special protocols that always should be treated as internal
870 aProtocols
[0] = "private:*";
871 aProtocols
[1] = "vnd.sun.star.*";
873 // get registered protocol handlers from configuration
874 Reference
< XNameAccess
> xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
875 const Sequence
< OUString
> aNames
= xAccess
->getElementNames();
876 for ( const auto& rName
: aNames
)
878 Reference
< XPropertySet
> xSet
;
879 Any aRet
= xAccess
->getByName( rName
);
884 aRet
= xSet
->getPropertyValue("Protocols");
885 Sequence
< OUString
> aTmp
;
888 aProtocols
.insert(aProtocols
.end(),aTmp
.begin(),aTmp
.end());
893 for (const OUString
& rProtocol
: aProtocols
)
895 WildCard
aPattern(rProtocol
);
896 if ( aPattern
.Matches( aURL
.Complete
) )
905 bool bLoadInternal
= false;
908 sfx2::openUriExternally(
909 aURL
.Complete
, pFilter
== nullptr);
911 catch ( css::system::SystemShellExecuteException
& )
913 rReq
.RemoveItem( SID_TARGETNAME
);
914 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_default" ) );
915 bLoadInternal
= true;
917 if ( !bLoadInternal
)
924 // hyperlink document must be loaded into a new frame
925 rReq
.RemoveItem( SID_TARGETNAME
);
926 rReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_default" ) );
931 if (!SvtSecurityOptions().isSecureMacroUri(aFileName
, aReferer
))
933 SfxErrorContext
aCtx( ERRCTX_SFX_OPENDOC
, aFileName
);
934 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED
);
938 SfxFrame
* pTargetFrame
= nullptr;
939 Reference
< XFrame
> xTargetFrame
;
941 const SfxFrameItem
* pFrameItem
= rReq
.GetArg
<SfxFrameItem
>(SID_DOCFRAME
);
943 pTargetFrame
= pFrameItem
->GetFrame();
947 const SfxUnoFrameItem
* pUnoFrameItem
= rReq
.GetArg
<SfxUnoFrameItem
>(SID_FILLFRAME
);
949 xTargetFrame
= pUnoFrameItem
->GetFrame();
952 if ( !pTargetFrame
&& !xTargetFrame
.is() && SfxViewFrame::Current() )
953 pTargetFrame
= &SfxViewFrame::Current()->GetFrame();
955 // check if caller has set a callback
956 std::unique_ptr
<SfxLinkItem
> pLinkItem
;
958 // remove from Itemset, because it confuses the parameter transformation
959 if (auto pParamLinkItem
= rReq
.GetArg
<SfxLinkItem
>(SID_DONELINK
))
960 pLinkItem
.reset(pParamLinkItem
->Clone());
962 rReq
.RemoveItem( SID_DONELINK
);
964 // check if the view must be hidden
965 bool bHidden
= false;
966 const SfxBoolItem
* pHidItem
= rReq
.GetArg
<SfxBoolItem
>(SID_HIDDEN
);
968 bHidden
= pHidItem
->GetValue();
970 // This request is a UI call. We have to set the right values inside the MediaDescriptor
971 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
972 // But we have to look for already existing values or for real hidden requests.
973 const SfxBoolItem
* pPreviewItem
= rReq
.GetArg
<SfxBoolItem
>(SID_PREVIEW
);
974 if (!bHidden
&& ( !pPreviewItem
|| !pPreviewItem
->GetValue() ) )
976 const SfxUnoAnyItem
* pInteractionItem
= rReq
.GetArg
<SfxUnoAnyItem
>(SID_INTERACTIONHANDLER
);
977 const SfxUInt16Item
* pMacroExecItem
= rReq
.GetArg
<SfxUInt16Item
>(SID_MACROEXECMODE
);
978 const SfxUInt16Item
* pDocTemplateItem
= rReq
.GetArg
<SfxUInt16Item
>(SID_UPDATEDOCMODE
);
980 if (!pInteractionItem
)
982 Reference
< task::XInteractionHandler2
> xHdl
= task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
983 rReq
.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER
,css::uno::makeAny(xHdl
)) );
986 rReq
.AppendItem( SfxUInt16Item(SID_MACROEXECMODE
,css::document::MacroExecMode::USE_CONFIG
) );
987 if (!pDocTemplateItem
)
988 rReq
.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE
,css::document::UpdateDocMode::ACCORDING_TO_CONFIG
) );
991 // extract target name
993 const SfxStringItem
* pTargetItem
= rReq
.GetArg
<SfxStringItem
>(SID_TARGETNAME
);
995 aTarget
= pTargetItem
->GetValue();
998 const SfxBoolItem
* pNewViewItem
= rReq
.GetArg
<SfxBoolItem
>(SID_OPEN_NEW_VIEW
);
999 if ( pNewViewItem
&& pNewViewItem
->GetValue() )
1000 aTarget
= "_blank" ;
1006 DBG_ASSERT( rReq
.IsSynchronCall() || pLinkItem
, "Hidden load process must be done synchronously!" );
1009 Reference
< XController
> xController
;
1010 // if a frame is given, it must be used for the starting point of the targeting mechanism
1011 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1012 if ( !xTargetFrame
.is() )
1016 xTargetFrame
= pTargetFrame
->GetFrameInterface();
1020 xTargetFrame
= Desktop::create(::comphelper::getProcessComponentContext());
1025 const SfxStringItem
* pURLItem
= rReq
.GetArg
<SfxStringItem
>(SID_FILE_NAME
);
1026 aFileName
= pURLItem
->GetValue();
1027 if( aFileName
.startsWith("#") ) // Mark without URL
1029 SfxViewFrame
*pView
= pTargetFrame
? pTargetFrame
->GetCurrentViewFrame() : nullptr;
1031 pView
= SfxViewFrame::Current();
1032 pView
->GetViewShell()->JumpToMark( aFileName
.copy(1) );
1033 rReq
.SetReturnValue( SfxViewFrameItem( pView
) );
1037 // convert items to properties for framework API calls
1038 Sequence
< PropertyValue
> aArgs
;
1039 TransformItems( SID_OPENDOC
, *rReq
.GetArgs(), aArgs
);
1040 // Any Referer (that was relevant in the above call to
1041 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1042 // this "open" request is initiated directly by the user:
1043 auto pArg
= std::find_if(aArgs
.begin(), aArgs
.end(),
1044 [](const PropertyValue
& rArg
) { return rArg
.Name
== "Referer"; });
1045 if (pArg
!= aArgs
.end())
1047 auto nIndex
= static_cast<sal_Int32
>(std::distance(aArgs
.begin(), pArg
));
1048 comphelper::removeElementAt(aArgs
, nIndex
);
1051 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1052 if( bHidden
|| pLinkItem
|| rReq
.IsSynchronCall() )
1054 // if loading must be done synchron, we must wait for completion to get a return value
1055 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1056 Reference
< XComponent
> xComp
;
1060 xComp
= ::comphelper::SynchronousDispatch::dispatch( xTargetFrame
, aFileName
, aTarget
, aArgs
);
1062 catch(const RuntimeException
&)
1066 catch(const css::uno::Exception
&)
1070 Reference
< XModel
> xModel( xComp
, UNO_QUERY
);
1072 xController
= xModel
->getCurrentController();
1074 xController
.set( xComp
, UNO_QUERY
);
1080 aURL
.Complete
= aFileName
;
1081 Reference
< util::XURLTransformer
> xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1082 xTrans
->parseStrict( aURL
);
1084 Reference
< XDispatchProvider
> xProv( xTargetFrame
, UNO_QUERY
);
1085 Reference
< XDispatch
> xDisp
= xProv
.is() ? xProv
->queryDispatch( aURL
, aTarget
, FrameSearchFlag::ALL
) : Reference
< XDispatch
>();
1087 xDisp
->dispatch( aURL
, aArgs
);
1090 if ( xController
.is() )
1092 // try to find the SfxFrame for the controller
1093 SfxFrame
* pCntrFrame
= nullptr;
1094 for ( SfxViewShell
* pShell
= SfxViewShell::GetFirst( false ); pShell
; pShell
= SfxViewShell::GetNext( *pShell
, false ) )
1096 if ( pShell
->GetController() == xController
)
1098 pCntrFrame
= &pShell
->GetViewFrame()->GetFrame();
1105 SfxObjectShell
* pSh
= pCntrFrame
->GetCurrentDocument();
1106 DBG_ASSERT( pSh
, "Controller without ObjectShell ?!" );
1108 rReq
.SetReturnValue( SfxViewFrameItem( pCntrFrame
->GetCurrentViewFrame() ) );
1111 pSh
->RestoreNoDelete();
1117 const SfxPoolItem
* pRetValue
= rReq
.GetReturnValue();
1120 pLinkItem
->GetValue().Call(pRetValue
);
1125 void SfxApplication::OpenRemoteExec_Impl( SfxRequest
& rReq
)
1127 rReq
.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG
, true ) );
1128 GetDispatcher_Impl()->Execute( SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs() );
1131 void SfxApplication::SignPDFExec_Impl(SfxRequest
& rReq
)
1133 rReq
.AppendItem(SfxBoolItem(SID_SIGNPDF
, true));
1134 GetDispatcher_Impl()->Execute(SID_OPENDOC
, SfxCallMode::SYNCHRON
, *rReq
.GetArgs());
1137 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */