1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <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> 45 46 #include <comphelper/processfactory.hxx> 47 #include <comphelper/sequence.hxx> 48 #include <comphelper/storagehelper.hxx> 49 #include <comphelper/synchronousdispatch.hxx> 50 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> 65 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> 87 88 #include <officecfg/Office/ProtocolHandler.hxx> 89 90 using namespace ::com::sun::star; 91 using namespace ::com::sun::star::beans; 92 using namespace ::com::sun::star::frame; 93 using namespace ::com::sun::star::lang; 94 using namespace ::com::sun::star::uno; 95 using namespace ::com::sun::star::util; 96 using namespace ::com::sun::star::task; 97 using namespace ::com::sun::star::container; 98 using namespace ::cppu; 99 using namespace ::sfx2; 100 101 void SetTemplate_Impl( const OUString &rFileName, 102 const OUString &rLongName, 103 SfxObjectShell *pDoc) 104 { 105 // write TemplateName to DocumentProperties of document 106 // TemplateDate stays as default (=current date) 107 pDoc->ResetFromTemplate( rLongName, rFileName ); 108 } 109 110 namespace { 111 112 class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier 113 { 114 public: 115 explicit SfxDocPasswordVerifier( const Reference< embed::XStorage >& rxStorage ) : 116 mxStorage( rxStorage ) {} 117 118 virtual ::comphelper::DocPasswordVerifierResult 119 verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override; 120 virtual ::comphelper::DocPasswordVerifierResult 121 verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override; 122 123 124 private: 125 Reference< embed::XStorage > mxStorage; 126 }; 127 128 } 129 130 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) 131 { 132 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword ); 133 return verifyEncryptionData( o_rEncryptionData ); 134 } 135 136 137 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) 138 { 139 ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; 140 try 141 { 142 // check the encryption data 143 // if the data correct is the stream will be opened successfully 144 // and immediately closed 145 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData ); 146 147 mxStorage->openStreamElement( 148 "content.xml", 149 embed::ElementModes::READ | embed::ElementModes::NOCREATE ); 150 151 // no exception -> success 152 eResult = ::comphelper::DocPasswordVerifierResult::OK; 153 } 154 catch( const packages::WrongPasswordException& ) 155 { 156 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; 157 } 158 catch( const uno::Exception& ) 159 { 160 // unknown error, report it as wrong password 161 // TODO/LATER: we need an additional way to report unknown problems in this case 162 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; 163 } 164 return eResult; 165 } 166 167 168 ErrCode CheckPasswd_Impl 169 ( 170 SfxObjectShell* pDoc, 171 SfxMedium* pFile // the Medium and its Password should be obtained 172 ) 173 174 /* [Description] 175 176 Ask for the password for a medium, only works if it concerns storage. 177 If the password flag is set in the Document Info, then the password is 178 requested through a user dialogue and the set at the Set of the medium. 179 If the set does not exist the it is created. 180 */ 181 { 182 ErrCode nRet = ERRCODE_NONE; 183 184 if( !pFile->GetFilter() || pFile->IsStorage() ) 185 { 186 uno::Reference< embed::XStorage > xStorage = pFile->GetStorage(); 187 if( xStorage.is() ) 188 { 189 uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY ); 190 if ( xStorageProps.is() ) 191 { 192 bool bIsEncrypted = false; 193 uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProperties; 194 try { 195 xStorageProps->getPropertyValue("HasEncryptedEntries") 196 >>= bIsEncrypted; 197 xStorageProps->getPropertyValue("EncryptionGpGProperties") 198 >>= aGpgProperties; 199 } catch( uno::Exception& ) 200 { 201 // TODO/LATER: 202 // the storage either has no encrypted elements or it's just 203 // does not allow to detect it, probably it should be implemented later 204 } 205 206 if ( bIsEncrypted ) 207 { 208 vcl::Window* pWin = pDoc ? pDoc->GetDialogParent( pFile ) : nullptr; 209 if ( pWin ) 210 pWin->Show(); 211 212 nRet = ERRCODE_SFX_CANTGETPASSWD; 213 214 SfxItemSet *pSet = pFile->GetItemSet(); 215 if( pSet ) 216 { 217 Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler(); 218 if( xInteractionHandler.is() ) 219 { 220 // use the comphelper password helper to request a password 221 OUString aPassword; 222 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_PASSWORD, false); 223 if ( pPasswordItem ) 224 aPassword = pPasswordItem->GetValue(); 225 226 uno::Sequence< beans::NamedValue > aEncryptionData; 227 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pSet, SID_ENCRYPTIONDATA, false); 228 if ( pEncryptionDataItem ) 229 pEncryptionDataItem->GetValue() >>= aEncryptionData; 230 231 // try if one of the public key entries is 232 // decryptable, then extract session key 233 // from it 234 if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() ) 235 aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties); 236 237 // tdf#93389: if recovering a document, encryption data should contain 238 // entries for the real filter, not only for recovery ODF, to keep it 239 // encrypted. Pass this in encryption data. 240 // TODO: pass here the real filter (from AutoRecovery::implts_openDocs) 241 // to marshal this to requestAndVerifyDocPassword 242 if (pSet->GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET) 243 { 244 aEncryptionData = comphelper::concatSequences( 245 aEncryptionData, std::initializer_list<beans::NamedValue>{ 246 { "ForSalvage", css::uno::Any(true) } }); 247 } 248 249 SfxDocPasswordVerifier aVerifier( xStorage ); 250 aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( 251 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard ); 252 253 pSet->ClearItem( SID_PASSWORD ); 254 pSet->ClearItem( SID_ENCRYPTIONDATA ); 255 256 if ( aEncryptionData.hasElements() ) 257 { 258 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) ); 259 260 try 261 { 262 // update the version list of the medium using the new password 263 pFile->GetVersionList(); 264 } 265 catch( uno::Exception& ) 266 { 267 // TODO/LATER: set the error code 268 } 269 270 nRet = ERRCODE_NONE; 271 } 272 else 273 nRet = ERRCODE_IO_ABORT; 274 } 275 } 276 } 277 } 278 else 279 { 280 OSL_FAIL( "A storage must implement XPropertySet interface!" ); 281 nRet = ERRCODE_SFX_CANTGETPASSWD; 282 } 283 } 284 } 285 286 return nRet; 287 } 288 289 290 ErrCode SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet ) 291 { 292 std::shared_ptr<const SfxFilter> pFilter; 293 SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) ); 294 295 if ( !aMedium.GetStorage( false ).is() ) 296 aMedium.GetInStream(); 297 298 if ( aMedium.GetError() ) 299 { 300 return aMedium.GetErrorCode(); 301 } 302 303 aMedium.UseInteractionHandler( true ); 304 ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE ); 305 if ( ERRCODE_NONE != nErr) 306 { 307 return ERRCODE_SFX_NOTATEMPLATE; 308 } 309 310 if( !pFilter || !pFilter->IsAllowedAsTemplate() ) 311 { 312 return ERRCODE_SFX_NOTATEMPLATE; 313 } 314 315 if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER ) 316 { 317 DBG_ASSERT( !xDoc.Is(), "Sorry, not implemented!" ); 318 SfxStringItem aName( SID_FILE_NAME, rFileName ); 319 SfxStringItem aReferer( SID_REFERER, "private:user" ); 320 SfxStringItem aFlags( SID_OPTIONS, "T" ); 321 SfxBoolItem aHidden( SID_HIDDEN, true ); 322 const SfxPoolItem *pRet = GetDispatcher_Impl()->ExecuteList( 323 SID_OPENDOC, SfxCallMode::SYNCHRON, 324 { &aName, &aHidden, &aReferer, &aFlags } ); 325 const SfxObjectItem *pObj = dynamic_cast<const SfxObjectItem*>( pRet ); 326 if ( pObj ) 327 xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() ); 328 else 329 { 330 const SfxViewFrameItem *pView = dynamic_cast<const SfxViewFrameItem*>( pRet ); 331 if ( pView ) 332 { 333 SfxViewFrame *pFrame = pView->GetFrame(); 334 if ( pFrame ) 335 xDoc = pFrame->GetObjectShell(); 336 } 337 } 338 339 if ( !xDoc.Is() ) 340 return ERRCODE_SFX_DOLOADFAILED; 341 } 342 else 343 { 344 if ( !xDoc.Is() ) 345 xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() ); 346 347 //pMedium takes ownership of pSet 348 SfxMedium *pMedium = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) ); 349 if(!xDoc->DoLoad(pMedium)) 350 { 351 ErrCode nErrCode = xDoc->GetErrorCode(); 352 xDoc->DoClose(); 353 xDoc.Clear(); 354 return nErrCode; 355 } 356 } 357 358 try 359 { 360 // TODO: introduce error handling 361 362 uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); 363 if( !xTempStorage.is() ) 364 throw uno::RuntimeException(); 365 366 xDoc->GetStorage()->copyToStorage( xTempStorage ); 367 368 if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) ) 369 throw uno::RuntimeException(); 370 } 371 catch( uno::Exception& ) 372 { 373 xDoc->DoClose(); 374 xDoc.Clear(); 375 376 // TODO: transfer correct error outside 377 return ERRCODE_SFX_GENERAL; 378 } 379 380 SetTemplate_Impl( rFileName, OUString(), xDoc ); 381 382 xDoc->SetNoName(); 383 xDoc->InvalidateName(); 384 xDoc->SetModified(false); 385 xDoc->ResetError(); 386 387 css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel(); 388 if ( xModel.is() ) 389 { 390 std::unique_ptr<SfxItemSet> pNew = xDoc->GetMedium()->GetItemSet()->Clone(); 391 pNew->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); 392 pNew->ClearItem( SID_FILTER_NAME ); 393 css::uno::Sequence< css::beans::PropertyValue > aArgs; 394 TransformItems( SID_OPENDOC, *pNew, aArgs ); 395 sal_Int32 nLength = aArgs.getLength(); 396 aArgs.realloc( nLength + 1 ); 397 aArgs[nLength].Name = "Title"; 398 aArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT ); 399 xModel->attachResource( OUString(), aArgs ); 400 } 401 402 return xDoc->GetErrorCode(); 403 } 404 405 406 void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq ) 407 { 408 const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT); 409 OUString aFactName; 410 if ( pFactoryItem ) 411 aFactName = pFactoryItem->GetValue(); 412 else 413 aFactName = SvtModuleOptions().GetDefaultModuleName(); 414 415 SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() ); 416 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) ); 417 aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) ); 418 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) ); 419 420 // TODO/LATER: Should the other arguments be transferred as well? 421 const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH); 422 if ( pDefaultPathItem ) 423 aReq.AppendItem( *pDefaultPathItem ); 424 const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME); 425 if ( pDefaultNameItem ) 426 aReq.AppendItem( *pDefaultNameItem ); 427 428 SfxGetpApp()->ExecuteSlot( aReq ); 429 const SfxViewFrameItem* pItem = dynamic_cast<const SfxViewFrameItem*>( aReq.GetReturnValue() ); 430 if ( pItem ) 431 rReq.SetReturnValue( SfxFrameItem( 0, pItem->GetFrame() ) ); 432 } 433 434 435 void SfxApplication::NewDocExec_Impl( SfxRequest& rReq ) 436 { 437 // No Parameter from BASIC only Factory given? 438 const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME); 439 const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); 440 const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME); 441 442 SfxObjectShellLock xDoc; 443 444 OUString aTemplateRegion, aTemplateName, aTemplateFileName; 445 bool bDirect = false; // through FileName instead of Region/Template 446 SfxErrorContext aEc(ERRCTX_SFX_NEWDOC); 447 if ( !pTemplNameItem && !pTemplFileNameItem ) 448 { 449 bool bNewWin = false; 450 vcl::Window* pTopWin = GetTopWindow(); 451 452 SfxObjectShell* pCurrentShell = SfxObjectShell::Current(); 453 Reference<XModel> xModel; 454 if(pCurrentShell) 455 xModel = pCurrentShell->GetModel(); 456 457 SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld()); 458 459 if (xModel.is()) 460 aTemplDlg.setDocumentModel(xModel); 461 462 int nRet = aTemplDlg.run(); 463 if ( nRet == RET_OK ) 464 { 465 rReq.Done(); 466 if ( pTopWin != GetTopWindow() ) 467 { 468 // the dialogue opens a document -> a new TopWindow appears 469 pTopWin = GetTopWindow(); 470 bNewWin = true; 471 } 472 } 473 474 if ( bNewWin && pTopWin ) 475 // after the destruction of the dialogue its parent comes to top, 476 // but we want that the new document is on top 477 pTopWin->ToTop(); 478 479 return; 480 } 481 else 482 { 483 // Template-Name 484 if ( pTemplNameItem ) 485 aTemplateName = pTemplNameItem->GetValue(); 486 487 // Template-Region 488 if ( pTemplRegionNameItem ) 489 aTemplateRegion = pTemplRegionNameItem->GetValue(); 490 491 // Template-File-Name 492 if ( pTemplFileNameItem ) 493 { 494 aTemplateFileName = pTemplFileNameItem->GetValue(); 495 bDirect = true; 496 } 497 } 498 499 ErrCode lErr = ERRCODE_NONE; 500 SfxItemSet* pSet = new SfxAllItemSet( GetPool() ); 501 pSet->Put( SfxBoolItem( SID_TEMPLATE, true ) ); 502 if ( !bDirect ) 503 { 504 SfxDocumentTemplates aTmpFac; 505 if( aTemplateFileName.isEmpty() ) 506 aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName ); 507 508 if( aTemplateFileName.isEmpty() ) 509 lErr = ERRCODE_SFX_TEMPLATENOTFOUND; 510 } 511 512 INetURLObject aObj( aTemplateFileName ); 513 SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() ); 514 515 if ( lErr != ERRCODE_NONE ) 516 { 517 ErrCode lFatalErr = lErr.IgnoreWarning(); 518 if ( lFatalErr ) 519 ErrorHandler::HandleError(lErr); 520 } 521 else 522 { 523 SfxCallMode eMode = SfxCallMode::SYNCHRON; 524 525 const SfxPoolItem *pRet=nullptr; 526 SfxStringItem aReferer( SID_REFERER, "private:user" ); 527 SfxStringItem aTarget( SID_TARGETNAME, "_default" ); 528 if ( !aTemplateFileName.isEmpty() ) 529 { 530 DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" ); 531 532 SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); 533 SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName ); 534 SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion ); 535 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode, 536 {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName}); 537 } 538 else 539 { 540 SfxStringItem aName( SID_FILE_NAME, "private:factory" ); 541 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode, 542 { &aName, &aTarget, &aReferer } ); 543 } 544 545 if ( pRet ) 546 rReq.SetReturnValue( *pRet ); 547 } 548 } 549 550 551 namespace { 552 553 /** 554 * Check if a given filter type should open the hyperlinked document 555 * natively. 556 * 557 * @param rFilter filter object 558 */ 559 bool lcl_isFilterNativelySupported(const SfxFilter& rFilter) 560 { 561 if (rFilter.IsOwnFormat()) 562 return true; 563 564 const OUString& aName = rFilter.GetFilterName(); 565 // We can handle all Excel variants natively. 566 return aName.startsWith("MS Excel"); 567 } 568 569 } 570 571 void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq ) 572 { 573 OUString aDocService; 574 const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE); 575 if (pDocSrvItem) 576 aDocService = pDocSrvItem->GetValue(); 577 578 sal_uInt16 nSID = rReq.GetSlot(); 579 const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); 580 if ( pFileNameItem ) 581 { 582 OUString aCommand( pFileNameItem->GetValue() ); 583 const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand ); 584 if ( pSlot ) 585 { 586 pFileNameItem = nullptr; 587 } 588 else 589 { 590 if ( aCommand.startsWith("slot:") ) 591 { 592 sal_uInt16 nSlotId = static_cast<sal_uInt16>(aCommand.copy(5).toInt32()); 593 if ( nSlotId == SID_OPENDOC ) 594 pFileNameItem = nullptr; 595 } 596 } 597 } 598 599 if ( !pFileNameItem ) 600 { 601 // get FileName from dialog 602 std::vector<OUString> aURLList; 603 OUString aFilter; 604 std::unique_ptr<SfxItemSet> pSet; 605 OUString aPath; 606 const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH); 607 if ( pFolderNameItem ) 608 aPath = pFolderNameItem->GetValue(); 609 else if ( nSID == SID_OPENTEMPLATE ) 610 { 611 aPath = SvtPathOptions().GetTemplatePath(); 612 if (!aPath.isEmpty()) // if not empty then get last token 613 aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not 614 } 615 616 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG; 617 const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG); 618 if ( pSystemDialogItem ) 619 nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO; 620 621 const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG); 622 if ( pRemoteDialogItem && pRemoteDialogItem->GetValue()) 623 nDialog = SFX2_IMPL_DIALOG_REMOTE; 624 625 sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION; 626 FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection; 627 const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF); 628 if (pSignPDFItem && pSignPDFItem->GetValue()) 629 { 630 eDialogFlags |= FileDialogFlags::SignPDF; 631 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE; 632 } 633 634 OUString sStandardDir; 635 636 const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR); 637 if ( pStandardDirItem ) 638 sStandardDir = pStandardDirItem->GetValue(); 639 640 css::uno::Sequence< OUString > aBlackList; 641 642 const SfxStringListItem* pBlackListItem = rReq.GetArg<SfxStringListItem>(SID_BLACK_LIST); 643 if ( pBlackListItem ) 644 pBlackListItem->GetStringList( aBlackList ); 645 646 vcl::Window* pTopWindow = GetTopWindow(); 647 ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow ? pTopWindow->GetFrameWeld() : nullptr, 648 nDialogType, 649 eDialogFlags, aURLList, 650 aFilter, pSet, &aPath, nDialog, sStandardDir, aBlackList); 651 652 if ( nErr == ERRCODE_ABORT ) 653 { 654 aURLList.clear(); 655 return; 656 } 657 658 rReq.SetArgs( *static_cast<SfxAllItemSet*>(pSet.get()) ); 659 if ( !aFilter.isEmpty() ) 660 rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) ); 661 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) ); 662 rReq.AppendItem( SfxStringItem( SID_REFERER, "private:user" ) ); 663 pSet.reset(); 664 665 if(!aURLList.empty()) 666 { 667 if ( nSID == SID_OPENTEMPLATE ) 668 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) ); 669 670 // This helper wraps an existing (or may new created InteractionHandler) 671 // intercept all incoming interactions and provide useful information 672 // later if the following transaction was finished. 673 674 sfx2::PreventDuplicateInteraction* pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext()); 675 uno::Reference<task::XInteractionHandler> xHandler(static_cast< css::task::XInteractionHandler* >(pHandler), css::uno::UNO_QUERY); 676 uno::Reference<task::XInteractionHandler> xWrappedHandler; 677 678 // wrap existing handler or create new UUI handler 679 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER); 680 if (pInteractionItem) 681 { 682 pInteractionItem->GetValue() >>= xWrappedHandler; 683 rReq.RemoveItem( SID_INTERACTIONHANDLER ); 684 } 685 if (xWrappedHandler.is()) 686 pHandler->setHandler(xWrappedHandler); 687 else 688 pHandler->useDefaultUUIHandler(); 689 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHandler)) ); 690 691 // define rules for this handler 692 css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get(); 693 ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction); 694 pHandler->addInteractionRule(aRule); 695 696 if (!aDocService.isEmpty()) 697 { 698 rReq.RemoveItem(SID_DOC_SERVICE); 699 rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService)); 700 } 701 702 for (auto const& url : aURLList) 703 { 704 rReq.RemoveItem( SID_FILE_NAME ); 705 rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) ); 706 707 // Run synchronous, so that not the next document is loaded 708 // when rescheduling 709 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished 710 // but only if reschedule is a problem 711 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() ); 712 713 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and 714 // break loop then. Otherwise we risk showing the same interaction more than once. 715 if ( pHandler->getInteractionInfo(aInteraction, &aRule) ) 716 { 717 if (aRule.m_nCallCount > 0) 718 { 719 if (aRule.m_xRequest.is()) 720 { 721 css::task::ErrorCodeRequest aRequest; 722 if (aRule.m_xRequest->getRequest() >>= aRequest) 723 { 724 if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED))) 725 break; 726 } 727 } 728 } 729 } 730 } 731 732 aURLList.clear(); 733 return; 734 } 735 aURLList.clear(); 736 } 737 738 bool bHyperlinkUsed = false; 739 740 if ( SID_OPENURL == nSID ) 741 { 742 // SID_OPENURL does the same as SID_OPENDOC! 743 rReq.SetSlot( SID_OPENDOC ); 744 } 745 else if ( nSID == SID_OPENTEMPLATE ) 746 { 747 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) ); 748 } 749 // pass URL to OS by using ShellExecuter or open it internal 750 // if it seems to be an own format. 751 /* Attention! 752 There exist two possibilities to open hyperlinks: 753 a) using SID_OPENHYPERLINK (new) 754 b) using SID_BROWSE (old) 755 */ 756 else if ( nSID == SID_OPENHYPERLINK ) 757 { 758 rReq.SetSlot( SID_OPENDOC ); 759 bHyperlinkUsed = true; 760 } 761 762 // no else here! It's optional ... 763 if (!bHyperlinkUsed) 764 { 765 const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE); 766 if ( pHyperLinkUsedItem ) 767 bHyperlinkUsed = pHyperLinkUsedItem->GetValue(); 768 // no "official" item, so remove it from ItemSet before using UNO-API 769 rReq.RemoveItem( SID_BROWSE ); 770 } 771 772 const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); 773 OUString aFileName = pFileName->GetValue(); 774 775 OUString aReferer; 776 const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER); 777 if ( pRefererItem ) 778 aReferer = pRefererItem->GetValue(); 779 780 const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS); 781 if ( pFileFlagsItem ) 782 { 783 const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase(); 784 if ( aFileFlags.indexOf('T') >= 0 ) 785 { 786 rReq.RemoveItem( SID_TEMPLATE ); 787 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) ); 788 } 789 790 if ( aFileFlags.indexOf('H') >= 0 ) 791 { 792 rReq.RemoveItem( SID_HIDDEN ); 793 rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) ); 794 } 795 796 if ( aFileFlags.indexOf('R') >= 0 ) 797 { 798 rReq.RemoveItem( SID_DOC_READONLY ); 799 rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) ); 800 } 801 802 if ( aFileFlags.indexOf('B') >= 0 ) 803 { 804 rReq.RemoveItem( SID_PREVIEW ); 805 rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) ); 806 } 807 808 rReq.RemoveItem( SID_OPTIONS ); 809 } 810 811 // Mark without URL cannot be handled by hyperlink code 812 if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' ) 813 { 814 uno::Reference<document::XTypeDetection> xTypeDetection( 815 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY); 816 817 if ( xTypeDetection.is() ) 818 { 819 URL aURL; 820 821 aURL.Complete = aFileName; 822 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) ); 823 xTrans->parseStrict( aURL ); 824 825 INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol(); 826 SvtExtendedSecurityOptions aExtendedSecurityOptions; 827 SvtExtendedSecurityOptions::OpenHyperlinkMode eMode = aExtendedSecurityOptions.GetOpenHyperlinkMode(); 828 829 if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp ) 830 { 831 SolarMutexGuard aGuard; 832 vcl::Window *pWindow = SfxGetpApp()->GetTopWindow(); 833 834 std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow ? pWindow->GetFrameWeld() : nullptr, 835 VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS))); 836 xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE)); 837 xSecurityWarningBox->run(); 838 return; 839 } 840 841 const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) }; 842 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher(); 843 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4EA( aTypeName ); 844 if (!pFilter || !lcl_isFilterNativelySupported(*pFilter)) 845 { 846 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS 847 if ( aINetProtocol == INetProtocol::Mailto ) 848 { 849 // don't dispatch mailto hyperlink to desktop dispatcher 850 rReq.RemoveItem( SID_TARGETNAME ); 851 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_self" ) ); 852 } 853 else if ( aINetProtocol == INetProtocol::Ftp || 854 aINetProtocol == INetProtocol::Http || 855 aINetProtocol == INetProtocol::Https ) 856 { 857 sfx2::openUriExternally(aURL.Complete, true); 858 return; 859 } 860 else 861 { 862 // check for "internal" protocols that should not be forwarded to the system 863 std::vector < OUString > aProtocols(2); 864 865 // add special protocols that always should be treated as internal 866 aProtocols[0] = "private:*"; 867 aProtocols[1] = "vnd.sun.star.*"; 868 869 // get registered protocol handlers from configuration 870 Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get()); 871 const Sequence < OUString > aNames = xAccess->getElementNames(); 872 for ( const auto& rName : aNames ) 873 { 874 Reference < XPropertySet > xSet; 875 Any aRet = xAccess->getByName( rName ); 876 aRet >>= xSet; 877 if ( xSet.is() ) 878 { 879 // copy protocols 880 aRet = xSet->getPropertyValue("Protocols"); 881 Sequence < OUString > aTmp; 882 aRet >>= aTmp; 883 884 aProtocols.insert(aProtocols.end(),aTmp.begin(),aTmp.end()); 885 } 886 } 887 888 bool bFound = false; 889 for (const OUString & rProtocol : aProtocols) 890 { 891 WildCard aPattern(rProtocol); 892 if ( aPattern.Matches( aURL.Complete ) ) 893 { 894 bFound = true; 895 break; 896 } 897 } 898 899 if ( !bFound ) 900 { 901 bool bLoadInternal = false; 902 try 903 { 904 sfx2::openUriExternally( 905 aURL.Complete, pFilter == nullptr); 906 } 907 catch ( css::system::SystemShellExecuteException& ) 908 { 909 rReq.RemoveItem( SID_TARGETNAME ); 910 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) ); 911 bLoadInternal = true; 912 } 913 if ( !bLoadInternal ) 914 return; 915 } 916 } 917 } 918 else 919 { 920 // hyperlink document must be loaded into a new frame 921 rReq.RemoveItem( SID_TARGETNAME ); 922 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) ); 923 } 924 } 925 } 926 927 if (!SvtSecurityOptions().isSecureMacroUri(aFileName, aReferer)) 928 { 929 SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName ); 930 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED ); 931 return; 932 } 933 934 SfxFrame* pTargetFrame = nullptr; 935 Reference< XFrame > xTargetFrame; 936 937 const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME); 938 if ( pFrameItem ) 939 pTargetFrame = pFrameItem->GetFrame(); 940 941 if ( !pTargetFrame ) 942 { 943 const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME); 944 if ( pUnoFrameItem ) 945 xTargetFrame = pUnoFrameItem->GetFrame(); 946 } 947 948 if ( !pTargetFrame && !xTargetFrame.is() && SfxViewFrame::Current() ) 949 pTargetFrame = &SfxViewFrame::Current()->GetFrame(); 950 951 // check if caller has set a callback 952 std::unique_ptr<SfxLinkItem> pLinkItem; 953 954 // remove from Itemset, because it confuses the parameter transformation 955 if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK)) 956 pLinkItem.reset(pParamLinkItem->Clone()); 957 958 rReq.RemoveItem( SID_DONELINK ); 959 960 // check if the view must be hidden 961 bool bHidden = false; 962 const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN); 963 if ( pHidItem ) 964 bHidden = pHidItem->GetValue(); 965 966 // This request is a UI call. We have to set the right values inside the MediaDescriptor 967 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate. 968 // But we have to look for already existing values or for real hidden requests. 969 const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW); 970 if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) ) 971 { 972 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER); 973 const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE); 974 const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE); 975 976 if (!pInteractionItem) 977 { 978 Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr ); 979 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHdl)) ); 980 } 981 if (!pMacroExecItem) 982 rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) ); 983 if (!pDocTemplateItem) 984 rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) ); 985 } 986 987 // extract target name 988 OUString aTarget; 989 const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME); 990 if ( pTargetItem ) 991 aTarget = pTargetItem->GetValue(); 992 else 993 { 994 const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW); 995 if ( pNewViewItem && pNewViewItem->GetValue() ) 996 aTarget = "_blank" ; 997 } 998 999 if ( bHidden ) 1000 { 1001 aTarget = "_blank"; 1002 DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" ); 1003 } 1004 1005 Reference < XController > xController; 1006 // if a frame is given, it must be used for the starting point of the targeting mechanism 1007 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron 1008 if ( !xTargetFrame.is() ) 1009 { 1010 if ( pTargetFrame ) 1011 { 1012 xTargetFrame = pTargetFrame->GetFrameInterface(); 1013 } 1014 else 1015 { 1016 xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext()); 1017 } 1018 } 1019 1020 // make URL ready 1021 const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); 1022 aFileName = pURLItem->GetValue(); 1023 if( aFileName.startsWith("#") ) // Mark without URL 1024 { 1025 SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr; 1026 if ( !pView ) 1027 pView = SfxViewFrame::Current(); 1028 pView->GetViewShell()->JumpToMark( aFileName.copy(1) ); 1029 rReq.SetReturnValue( SfxViewFrameItem( pView ) ); 1030 return; 1031 } 1032 1033 // convert items to properties for framework API calls 1034 Sequence < PropertyValue > aArgs; 1035 TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs ); 1036 // Any Referer (that was relevant in the above call to 1037 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming 1038 // this "open" request is initiated directly by the user: 1039 auto pArg = std::find_if(aArgs.begin(), aArgs.end(), 1040 [](const PropertyValue& rArg) { return rArg.Name == "Referer"; }); 1041 if (pArg != aArgs.end()) 1042 { 1043 auto nIndex = static_cast<sal_Int32>(std::distance(aArgs.begin(), pArg)); 1044 comphelper::removeElementAt(aArgs, nIndex); 1045 } 1046 1047 // TODO/LATER: either remove LinkItem or create an asynchronous process for it 1048 if( bHidden || pLinkItem || rReq.IsSynchronCall() ) 1049 { 1050 // if loading must be done synchron, we must wait for completion to get a return value 1051 // find frame by myself; I must know the exact frame to get the controller for the return value from it 1052 Reference < XComponent > xComp; 1053 1054 try 1055 { 1056 xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs ); 1057 } 1058 catch(const RuntimeException&) 1059 { 1060 throw; 1061 } 1062 catch(const css::uno::Exception&) 1063 { 1064 } 1065 1066 Reference < XModel > xModel( xComp, UNO_QUERY ); 1067 if ( xModel.is() ) 1068 xController = xModel->getCurrentController(); 1069 else 1070 xController.set( xComp, UNO_QUERY ); 1071 1072 } 1073 else 1074 { 1075 URL aURL; 1076 aURL.Complete = aFileName; 1077 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) ); 1078 xTrans->parseStrict( aURL ); 1079 1080 Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY ); 1081 Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >(); 1082 if ( xDisp.is() ) 1083 xDisp->dispatch( aURL, aArgs ); 1084 } 1085 1086 if ( xController.is() ) 1087 { 1088 // try to find the SfxFrame for the controller 1089 SfxFrame* pCntrFrame = nullptr; 1090 for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) ) 1091 { 1092 if ( pShell->GetController() == xController ) 1093 { 1094 pCntrFrame = &pShell->GetViewFrame()->GetFrame(); 1095 break; 1096 } 1097 } 1098 1099 if ( pCntrFrame ) 1100 { 1101 SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument(); 1102 DBG_ASSERT( pSh, "Controller without ObjectShell ?!" ); 1103 1104 rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) ); 1105 1106 if ( bHidden ) 1107 pSh->RestoreNoDelete(); 1108 } 1109 } 1110 1111 if (pLinkItem) 1112 { 1113 const SfxPoolItem* pRetValue = rReq.GetReturnValue(); 1114 if (pRetValue) 1115 { 1116 pLinkItem->GetValue().Call(pRetValue); 1117 } 1118 } 1119 } 1120 1121 void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq ) 1122 { 1123 rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) ); 1124 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() ); 1125 } 1126 1127 void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq) 1128 { 1129 rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true)); 1130 GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs()); 1131 } 1132 1133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1134
