LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / appl / appopen.cxx
blob5d8a28b7d21c1a6e2bc0fbeaf7e9feb7eb7d64a7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 );
111 namespace {
113 class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
115 public:
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;
125 private:
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(
149 "content.xml",
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;
165 return eResult;
169 ErrCode CheckPasswd_Impl
171 SfxObjectShell* pDoc,
172 SfxMedium* pFile // the Medium and its Password should be obtained
175 /* [Description]
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();
188 if( xStorage.is() )
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;
195 try {
196 xStorageProps->getPropertyValue("HasEncryptedEntries")
197 >>= bIsEncrypted;
198 xStorageProps->getPropertyValue("EncryptionGpGProperties")
199 >>= aGpgProperties;
200 } catch( uno::Exception& )
202 // TODO/LATER:
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
207 if ( bIsEncrypted )
209 css::uno::Reference<css::awt::XWindow> xWin(pDoc ? pDoc->GetDialogParent(pFile) : nullptr);
210 if (xWin)
211 xWin->setVisible(true);
213 nRet = ERRCODE_SFX_CANTGETPASSWD;
215 SfxItemSet *pSet = pFile->GetItemSet();
216 if( pSet )
218 Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler();
219 if( xInteractionHandler.is() )
221 // use the comphelper password helper to request a password
222 OUString aPassword;
223 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_PASSWORD, false);
224 if ( pPasswordItem )
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
234 // from it
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
271 nRet = ERRCODE_NONE;
273 else
274 nRet = ERRCODE_IO_ABORT;
279 else
281 OSL_FAIL( "A storage must implement XPropertySet interface!" );
282 nRet = ERRCODE_SFX_CANTGETPASSWD;
287 return nRet;
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 );
327 if ( pObj )
328 xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() );
329 else
331 const SfxViewFrameItem *pView = dynamic_cast<const SfxViewFrameItem*>( pRet );
332 if ( pView )
334 SfxViewFrame *pFrame = pView->GetFrame();
335 if ( pFrame )
336 xDoc = pFrame->GetObjectShell();
340 if ( !xDoc.Is() )
341 return ERRCODE_SFX_DOLOADFAILED;
343 else
345 if ( !xDoc.Is() )
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();
353 xDoc->DoClose();
354 xDoc.Clear();
355 return nErrCode;
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& )
374 xDoc->DoClose();
375 xDoc.Clear();
377 // TODO: transfer correct error outside
378 return ERRCODE_SFX_GENERAL;
381 SetTemplate_Impl( rFileName, OUString(), xDoc );
383 xDoc->SetNoName();
384 xDoc->InvalidateName();
385 xDoc->SetModified(false);
386 xDoc->ResetError();
388 css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel();
389 if ( xModel.is() )
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 auto pArgs = aArgs.getArray();
399 pArgs[nLength].Name = "Title";
400 pArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT );
401 xModel->attachResource( OUString(), aArgs );
404 return xDoc->GetErrorCode();
408 void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq )
410 const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT);
411 OUString aFactName;
412 if ( pFactoryItem )
413 aFactName = pFactoryItem->GetValue();
414 else
415 aFactName = SvtModuleOptions().GetDefaultModuleName();
417 SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() );
418 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) );
419 aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) );
420 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
422 // TODO/LATER: Should the other arguments be transferred as well?
423 const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH);
424 if ( pDefaultPathItem )
425 aReq.AppendItem( *pDefaultPathItem );
426 const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME);
427 if ( pDefaultNameItem )
428 aReq.AppendItem( *pDefaultNameItem );
430 SfxGetpApp()->ExecuteSlot( aReq );
431 const SfxViewFrameItem* pItem = dynamic_cast<const SfxViewFrameItem*>( aReq.GetReturnValue() );
432 if ( pItem )
433 rReq.SetReturnValue( SfxFrameItem( 0, pItem->GetFrame() ) );
436 void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet )
438 rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
441 void SfxApplication::NewDocExec_Impl( SfxRequest& rReq )
443 // No Parameter from BASIC only Factory given?
444 const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME);
445 const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
446 const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME);
448 SfxObjectShellLock xDoc;
450 OUString aTemplateRegion, aTemplateName, aTemplateFileName;
451 bool bDirect = false; // through FileName instead of Region/Template
452 SfxErrorContext aEc(ERRCTX_SFX_NEWDOC);
453 if ( !pTemplNameItem && !pTemplFileNameItem )
455 bool bNewWin = false;
456 weld::Window* pTopWin = GetTopWindow();
458 SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
459 Reference<XModel> xModel;
460 if(pCurrentShell)
461 xModel = pCurrentShell->GetModel();
463 SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld());
465 if (xModel.is())
466 aTemplDlg.setDocumentModel(xModel);
468 int nRet = aTemplDlg.run();
469 if ( nRet == RET_OK )
471 rReq.Done();
472 if ( pTopWin != GetTopWindow() )
474 // the dialogue opens a document -> a new TopWindow appears
475 pTopWin = GetTopWindow();
476 bNewWin = true;
480 if (bNewWin && pTopWin)
482 // after the destruction of the dialogue its parent comes to top,
483 // but we want that the new document is on top
484 pTopWin->present();
487 return;
489 else
491 // Template-Name
492 if ( pTemplNameItem )
493 aTemplateName = pTemplNameItem->GetValue();
495 // Template-Region
496 if ( pTemplRegionNameItem )
497 aTemplateRegion = pTemplRegionNameItem->GetValue();
499 // Template-File-Name
500 if ( pTemplFileNameItem )
502 aTemplateFileName = pTemplFileNameItem->GetValue();
503 bDirect = true;
507 ErrCode lErr = ERRCODE_NONE;
508 if ( !bDirect )
510 SfxDocumentTemplates aTmpFac;
511 if( aTemplateFileName.isEmpty() )
512 aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName );
514 if( aTemplateFileName.isEmpty() )
515 lErr = ERRCODE_SFX_TEMPLATENOTFOUND;
518 INetURLObject aObj( aTemplateFileName );
519 SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() );
521 if ( lErr != ERRCODE_NONE )
523 ErrCode lFatalErr = lErr.IgnoreWarning();
524 if ( lFatalErr )
525 ErrorHandler::HandleError(lErr);
527 else
529 SfxCallMode eMode = SfxCallMode::SYNCHRON;
531 const SfxPoolItem *pRet=nullptr;
532 SfxStringItem aReferer( SID_REFERER, "private:user" );
533 SfxStringItem aTarget( SID_TARGETNAME, "_default" );
534 if ( !aTemplateFileName.isEmpty() )
536 DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
538 SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
539 SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName );
540 SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion );
541 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
542 {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName});
544 else
546 SfxStringItem aName( SID_FILE_NAME, "private:factory" );
547 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
548 { &aName, &aTarget, &aReferer } );
551 if ( pRet )
552 rReq.SetReturnValue( *pRet );
557 namespace {
560 * Check if a given filter type should open the hyperlinked document
561 * natively.
563 * @param rFilter filter object
565 bool lcl_isFilterNativelySupported(const SfxFilter& rFilter)
567 if (rFilter.IsOwnFormat())
568 return true;
570 const OUString& aName = rFilter.GetFilterName();
571 // We can handle all Excel variants natively.
572 return aName.startsWith("MS Excel");
577 void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq )
579 OUString aDocService;
580 const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE);
581 if (pDocSrvItem)
582 aDocService = pDocSrvItem->GetValue();
584 sal_uInt16 nSID = rReq.GetSlot();
585 const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
586 if ( pFileNameItem )
588 OUString aCommand( pFileNameItem->GetValue() );
589 const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand );
590 if ( pSlot )
592 pFileNameItem = nullptr;
594 else
596 if ( aCommand.startsWith("slot:") )
598 sal_uInt16 nSlotId = static_cast<sal_uInt16>(aCommand.copy(5).toInt32());
599 if ( nSlotId == SID_OPENDOC )
600 pFileNameItem = nullptr;
605 if ( !pFileNameItem )
607 // get FileName from dialog
608 std::vector<OUString> aURLList;
609 OUString aFilter;
610 std::optional<SfxAllItemSet> pSet;
611 OUString aPath;
612 const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH);
613 if ( pFolderNameItem )
614 aPath = pFolderNameItem->GetValue();
615 else if ( nSID == SID_OPENTEMPLATE )
617 aPath = SvtPathOptions().GetTemplatePath();
618 if (!aPath.isEmpty()) // if not empty then get last token
619 aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
622 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
623 const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG);
624 if ( pSystemDialogItem )
625 nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO;
627 const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG);
628 if ( pRemoteDialogItem && pRemoteDialogItem->GetValue())
629 nDialog = SFX2_IMPL_DIALOG_REMOTE;
631 sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION;
632 FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection;
633 const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF);
634 if (pSignPDFItem && pSignPDFItem->GetValue())
636 eDialogFlags |= FileDialogFlags::SignPDF;
637 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
640 OUString sStandardDir;
642 const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR);
643 if ( pStandardDirItem )
644 sStandardDir = pStandardDirItem->GetValue();
646 css::uno::Sequence< OUString > aDenyList;
648 const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST);
649 if ( pDenyListItem )
650 pDenyListItem->GetStringList( aDenyList );
652 weld::Window* pTopWindow = GetTopWindow();
653 ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow,
654 nDialogType,
655 eDialogFlags, aURLList,
656 aFilter, pSet, &aPath, nDialog, sStandardDir, aDenyList);
658 if ( nErr == ERRCODE_ABORT )
660 aURLList.clear();
661 return;
664 rReq.SetArgs( *pSet );
665 if ( !aFilter.isEmpty() )
666 rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) );
667 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
668 rReq.AppendItem( SfxStringItem( SID_REFERER, "private:user" ) );
669 pSet.reset();
671 if(!aURLList.empty())
673 if ( nSID == SID_OPENTEMPLATE )
674 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
676 // This helper wraps an existing (or may new created InteractionHandler)
677 // intercept all incoming interactions and provide useful information
678 // later if the following transaction was finished.
680 rtl::Reference<sfx2::PreventDuplicateInteraction> pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
681 uno::Reference<task::XInteractionHandler> xHandler(pHandler);
682 uno::Reference<task::XInteractionHandler> xWrappedHandler;
684 // wrap existing handler or create new UUI handler
685 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
686 if (pInteractionItem)
688 pInteractionItem->GetValue() >>= xWrappedHandler;
689 rReq.RemoveItem( SID_INTERACTIONHANDLER );
691 if (xWrappedHandler.is())
692 pHandler->setHandler(xWrappedHandler);
693 else
694 pHandler->useDefaultUUIHandler();
695 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHandler)) );
697 // define rules for this handler
698 css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get();
699 ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction);
700 pHandler->addInteractionRule(aRule);
702 if (!aDocService.isEmpty())
704 rReq.RemoveItem(SID_DOC_SERVICE);
705 rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService));
708 for (auto const& url : aURLList)
710 rReq.RemoveItem( SID_FILE_NAME );
711 rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) );
713 // Run synchronous, so that not the next document is loaded
714 // when rescheduling
715 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
716 // but only if reschedule is a problem
717 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
719 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
720 // break loop then. Otherwise we risk showing the same interaction more than once.
721 if ( pHandler->getInteractionInfo(aInteraction, &aRule) )
723 if (aRule.m_nCallCount > 0)
725 if (aRule.m_xRequest.is())
727 css::task::ErrorCodeRequest aRequest;
728 if (aRule.m_xRequest->getRequest() >>= aRequest)
730 if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED)))
731 break;
738 aURLList.clear();
739 return;
741 aURLList.clear();
744 bool bHyperlinkUsed = false;
746 if ( SID_OPENURL == nSID )
748 // SID_OPENURL does the same as SID_OPENDOC!
749 rReq.SetSlot( SID_OPENDOC );
751 else if ( nSID == SID_OPENTEMPLATE )
753 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
755 // pass URL to OS by using ShellExecuter or open it internal
756 // if it seems to be an own format.
757 /* Attention!
758 There exist two possibilities to open hyperlinks:
759 a) using SID_OPENHYPERLINK (new)
760 b) using SID_BROWSE (old)
762 else if ( nSID == SID_OPENHYPERLINK )
764 rReq.SetSlot( SID_OPENDOC );
765 bHyperlinkUsed = true;
768 // no else here! It's optional ...
769 if (!bHyperlinkUsed)
771 const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE);
772 if ( pHyperLinkUsedItem )
773 bHyperlinkUsed = pHyperLinkUsedItem->GetValue();
774 // no "official" item, so remove it from ItemSet before using UNO-API
775 rReq.RemoveItem( SID_BROWSE );
778 const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
779 OUString aFileName = pFileName->GetValue();
781 OUString aReferer;
782 const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
783 if ( pRefererItem )
784 aReferer = pRefererItem->GetValue();
786 const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS);
787 if ( pFileFlagsItem )
789 const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase();
790 if ( aFileFlags.indexOf('T') >= 0 )
792 rReq.RemoveItem( SID_TEMPLATE );
793 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) );
796 if ( aFileFlags.indexOf('H') >= 0 )
798 rReq.RemoveItem( SID_HIDDEN );
799 rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
802 if ( aFileFlags.indexOf('R') >= 0 )
804 rReq.RemoveItem( SID_DOC_READONLY );
805 rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) );
808 if ( aFileFlags.indexOf('B') >= 0 )
810 rReq.RemoveItem( SID_PREVIEW );
811 rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) );
814 rReq.RemoveItem( SID_OPTIONS );
817 // Mark without URL cannot be handled by hyperlink code
818 if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' )
820 uno::Reference<document::XTypeDetection> xTypeDetection(
821 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY);
823 if ( xTypeDetection.is() )
825 URL aURL;
827 aURL.Complete = aFileName;
828 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
829 xTrans->parseStrict( aURL );
831 INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol();
832 auto eMode = officecfg::Office::Security::Hyperlinks::Open::get();
834 if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp )
836 SolarMutexGuard aGuard;
837 weld::Window *pWindow = SfxGetpApp()->GetTopWindow();
839 std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow,
840 VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS)));
841 xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE));
842 xSecurityWarningBox->run();
843 return;
846 const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) };
847 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
848 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4EA( aTypeName );
849 if (!pFilter || !lcl_isFilterNativelySupported(*pFilter))
851 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
852 if ( aINetProtocol == INetProtocol::Mailto )
854 // don't dispatch mailto hyperlink to desktop dispatcher
855 rReq.RemoveItem( SID_TARGETNAME );
856 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_self" ) );
858 else if ( aINetProtocol == INetProtocol::Ftp ||
859 aINetProtocol == INetProtocol::Http ||
860 aINetProtocol == INetProtocol::Https )
862 sfx2::openUriExternally(aURL.Complete, true, rReq.GetFrameWeld());
863 return;
865 else
867 // check for "internal" protocols that should not be forwarded to the system
868 // add special protocols that always should be treated as internal
869 std::vector < OUString > aProtocols { "private:*", "vnd.sun.star.*" };
871 // get registered protocol handlers from configuration
872 Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
873 const Sequence < OUString > aNames = xAccess->getElementNames();
874 for ( const auto& rName : aNames )
876 Reference < XPropertySet > xSet;
877 Any aRet = xAccess->getByName( rName );
878 aRet >>= xSet;
879 if ( xSet.is() )
881 // copy protocols
882 aRet = xSet->getPropertyValue("Protocols");
883 Sequence < OUString > aTmp;
884 aRet >>= aTmp;
886 aProtocols.insert(aProtocols.end(),std::cbegin(aTmp),std::cend(aTmp));
890 bool bFound = false;
891 for (const OUString & rProtocol : aProtocols)
893 WildCard aPattern(rProtocol);
894 if ( aPattern.Matches( aURL.Complete ) )
896 bFound = true;
897 break;
901 if ( !bFound )
903 bool bLoadInternal = false;
906 sfx2::openUriExternally(
907 aURL.Complete, pFilter == nullptr, rReq.GetFrameWeld());
909 catch ( css::system::SystemShellExecuteException& )
911 rReq.RemoveItem( SID_TARGETNAME );
912 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
913 bLoadInternal = true;
915 if ( !bLoadInternal )
916 return;
920 else
922 // hyperlink document must be loaded into a new frame
923 rReq.RemoveItem( SID_TARGETNAME );
924 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
929 if (!SvtSecurityOptions::isSecureMacroUri(aFileName, aReferer))
931 SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName );
932 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED );
933 return;
936 SfxFrame* pTargetFrame = nullptr;
937 Reference< XFrame > xTargetFrame;
939 const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
940 if ( pFrameItem )
941 pTargetFrame = pFrameItem->GetFrame();
943 if ( !pTargetFrame )
945 const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
946 if ( pUnoFrameItem )
947 xTargetFrame = pUnoFrameItem->GetFrame();
950 if ( !pTargetFrame && !xTargetFrame.is() && SfxViewFrame::Current() )
951 pTargetFrame = &SfxViewFrame::Current()->GetFrame();
953 // check if caller has set a callback
954 std::unique_ptr<SfxLinkItem> pLinkItem;
956 // remove from Itemset, because it confuses the parameter transformation
957 if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK))
958 pLinkItem.reset(pParamLinkItem->Clone());
960 rReq.RemoveItem( SID_DONELINK );
962 // check if the view must be hidden
963 bool bHidden = false;
964 const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN);
965 if ( pHidItem )
966 bHidden = pHidItem->GetValue();
968 // This request is a UI call. We have to set the right values inside the MediaDescriptor
969 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
970 // But we have to look for already existing values or for real hidden requests.
971 const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW);
972 if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) )
974 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
975 const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE);
976 const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE);
978 if (!pInteractionItem)
980 Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
981 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHdl)) );
983 if (!pMacroExecItem)
984 rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
985 if (!pDocTemplateItem)
986 rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
989 // extract target name
990 OUString aTarget;
991 const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME);
992 if ( pTargetItem )
993 aTarget = pTargetItem->GetValue();
994 else
996 const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW);
997 if ( pNewViewItem && pNewViewItem->GetValue() )
998 aTarget = "_blank" ;
1001 if ( bHidden )
1003 aTarget = "_blank";
1004 DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" );
1007 Reference < XController > xController;
1008 // if a frame is given, it must be used for the starting point of the targeting mechanism
1009 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1010 if ( !xTargetFrame.is() )
1012 if ( pTargetFrame )
1014 xTargetFrame = pTargetFrame->GetFrameInterface();
1016 else
1018 xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext());
1022 // make URL ready
1023 const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
1024 aFileName = pURLItem->GetValue();
1025 if( aFileName.startsWith("#") ) // Mark without URL
1027 SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr;
1028 if ( !pView )
1029 pView = SfxViewFrame::Current();
1030 pView->GetViewShell()->JumpToMark( aFileName.copy(1) );
1031 rReq.SetReturnValue( SfxViewFrameItem( pView ) );
1032 return;
1035 // convert items to properties for framework API calls
1036 Sequence < PropertyValue > aArgs;
1037 TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs );
1038 // Any Referer (that was relevant in the above call to
1039 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1040 // this "open" request is initiated directly by the user:
1041 auto pArg = std::find_if(std::cbegin(aArgs), std::cend(aArgs),
1042 [](const PropertyValue& rArg) { return rArg.Name == "Referer"; });
1043 if (pArg != std::cend(aArgs))
1045 auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(aArgs), pArg));
1046 comphelper::removeElementAt(aArgs, nIndex);
1049 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1050 if( bHidden || pLinkItem || rReq.IsSynchronCall() )
1052 // if loading must be done synchron, we must wait for completion to get a return value
1053 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1054 Reference < XComponent > xComp;
1058 xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs );
1060 catch(const RuntimeException&)
1062 throw;
1064 catch(const css::uno::Exception&)
1068 Reference < XModel > xModel( xComp, UNO_QUERY );
1069 if ( xModel.is() )
1070 xController = xModel->getCurrentController();
1071 else
1072 xController.set( xComp, UNO_QUERY );
1075 else
1077 URL aURL;
1078 aURL.Complete = aFileName;
1079 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1080 xTrans->parseStrict( aURL );
1082 Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY );
1083 Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >();
1084 if ( xDisp.is() )
1085 xDisp->dispatch( aURL, aArgs );
1088 if ( xController.is() )
1090 // try to find the SfxFrame for the controller
1091 SfxFrame* pCntrFrame = nullptr;
1092 for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) )
1094 if ( pShell->GetController() == xController )
1096 pCntrFrame = &pShell->GetViewFrame()->GetFrame();
1097 break;
1101 if ( pCntrFrame )
1103 SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument();
1104 DBG_ASSERT( pSh, "Controller without ObjectShell ?!" );
1106 rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) );
1108 if ( bHidden )
1109 pSh->RestoreNoDelete();
1113 if (pLinkItem)
1115 const SfxPoolItem* pRetValue = rReq.GetReturnValue();
1116 if (pRetValue)
1118 pLinkItem->GetValue().Call(pRetValue);
1123 void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq )
1125 rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) );
1126 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
1129 void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq)
1131 rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true));
1132 GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs());
1135 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */