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