1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sfx2.hxx" 30 // includes -------------------------------------------------------------- 31 #include <com/sun/star/beans/PropertyValue.hpp> 32 #include <com/sun/star/beans/XPropertyAccess.hpp> 33 #include <com/sun/star/frame/XFrame.hpp> 34 #include <com/sun/star/frame/XModel.hpp> 35 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 36 #include <com/sun/star/ucb/CommandAbortedException.hpp> 37 #include <com/sun/star/uno/Reference.h> 38 #include <com/sun/star/util/XURLTransformer.hpp> 39 #include <com/sun/star/system/XSimpleMailClientSupplier.hpp> 40 #include <com/sun/star/system/SimpleMailClientFlags.hpp> 41 #include <com/sun/star/embed/XStorage.hpp> 42 #include <com/sun/star/embed/ElementModes.hpp> 43 #include <com/sun/star/embed/XTransactedObject.hpp> 44 #include <com/sun/star/container/XContainerQuery.hpp> 45 #include <com/sun/star/util/XModifiable.hpp> 46 #include <com/sun/star/frame/XModuleManager.hpp> 47 #include <com/sun/star/frame/XStorable.hpp> 48 #include <com/sun/star/beans/XPropertySet.hpp> 49 #include <com/sun/star/security/CertificateValidity.hpp> 50 #include <com/sun/star/security/DocumentSignatureInformation.hpp> 51 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> 52 #include <com/sun/star/frame/XDispatchProvider.hpp> 53 #include <com/sun/star/frame/XDispatch.hpp> 54 #include <com/sun/star/frame/XStatusListener.hpp> 55 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 56 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> 57 #include <com/sun/star/document/XExporter.hpp> 58 #include <rtl/textenc.h> 59 #include <rtl/uri.h> 60 #include <rtl/uri.hxx> 61 #include <rtl/ustrbuf.hxx> 62 #include <vcl/msgbox.hxx> 63 64 #include <sfx2/mailmodelapi.hxx> 65 #include "sfxtypes.hxx" 66 #include "sfx2/sfxresid.hxx" 67 #include <sfx2/sfxsids.hrc> 68 #include "dialog.hrc" 69 70 #include <unotools/tempfile.hxx> 71 #include <unotools/configitem.hxx> 72 #include <ucbhelper/content.hxx> 73 #include <tools/urlobj.hxx> 74 #include <unotools/useroptions.hxx> 75 #include <comphelper/processfactory.hxx> 76 #include <comphelper/extract.hxx> 77 #include <comphelper/storagehelper.hxx> 78 #include <comphelper/sequenceasvector.hxx> 79 #include <comphelper/sequenceashashmap.hxx> 80 #include <comphelper/mediadescriptor.hxx> 81 #include <toolkit/helper/vclunohelper.hxx> 82 #include <vcl/svapp.hxx> 83 #include <cppuhelper/implbase1.hxx> 84 85 // -------------------------------------------------------------- 86 using namespace ::com::sun::star; 87 using namespace ::com::sun::star::beans; 88 using namespace ::com::sun::star::frame; 89 using namespace ::com::sun::star::io; 90 using namespace ::com::sun::star::lang; 91 using namespace ::com::sun::star::ucb; 92 using namespace ::com::sun::star::uno; 93 using namespace ::com::sun::star::util; 94 using namespace ::com::sun::star::system; 95 using namespace ::rtl; 96 97 namespace css = ::com::sun::star; 98 // - class PrepareListener_Impl ------------------------------------------ 99 class PrepareListener_Impl : public ::cppu::WeakImplHelper1< css::frame::XStatusListener > 100 { 101 bool m_bState; 102 public: 103 PrepareListener_Impl(); 104 virtual ~PrepareListener_Impl(); 105 106 // css.frame.XStatusListener 107 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent) 108 throw(css::uno::RuntimeException); 109 110 // css.lang.XEventListener 111 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) 112 throw(css::uno::RuntimeException); 113 114 bool IsSet() const {return m_bState;} 115 }; 116 117 /*-- 25.08.2010 14:32:49--------------------------------------------------- 118 119 -----------------------------------------------------------------------*/ 120 PrepareListener_Impl::PrepareListener_Impl() : 121 m_bState( false ) 122 { 123 } 124 /*-- 25.08.2010 14:32:51--------------------------------------------------- 125 126 -----------------------------------------------------------------------*/ 127 PrepareListener_Impl::~PrepareListener_Impl() 128 { 129 } 130 /*-- 25.08.2010 14:32:51--------------------------------------------------- 131 132 -----------------------------------------------------------------------*/ 133 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent) throw(css::uno::RuntimeException) 134 { 135 if( rEvent.IsEnabled ) 136 rEvent.State >>= m_bState; 137 else 138 m_bState = sal_False; 139 } 140 /*-- 25.08.2010 14:32:52--------------------------------------------------- 141 142 -----------------------------------------------------------------------*/ 143 void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/) throw(css::uno::RuntimeException) 144 { 145 } 146 147 // class AddressList_Impl ------------------------------------------------ 148 149 typedef String* AddressItemPtr_Impl; 150 DECLARE_LIST( AddressList_Impl, AddressItemPtr_Impl ) 151 152 // class SfxMailModel ----------------------------------------------- 153 154 static const char PDF_DOCUMENT_TYPE[] = "pdf_Portable_Document_Format"; 155 static const sal_uInt32 PDF_DOCUMENT_TYPE_LEN = 28; 156 157 void SfxMailModel::ClearList( AddressList_Impl* pList ) 158 { 159 if ( pList ) 160 { 161 sal_uIntPtr i, nCount = pList->Count(); 162 for ( i = 0; i < nCount; ++i ) 163 delete pList->GetObject(i); 164 pList->Clear(); 165 } 166 } 167 168 void SfxMailModel::MakeValueList( AddressList_Impl* pList, String& rValueList ) 169 { 170 rValueList.Erase(); 171 if ( pList ) 172 { 173 sal_uIntPtr i, nCount = pList->Count(); 174 for ( i = 0; i < nCount; ++i ) 175 { 176 if ( rValueList.Len() > 0 ) 177 rValueList += ','; 178 rValueList += *pList->GetObject(i); 179 } 180 } 181 } 182 183 sal_Bool HasDocumentValidSignature( const css::uno::Reference< css::frame::XModel >& xModel ) 184 { 185 try 186 { 187 css::uno::Reference< css::beans::XPropertySet > xPropSet( xModel, css::uno::UNO_QUERY ); 188 if ( xPropSet.is() ) 189 { 190 Any a = xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HasValidSignatures" ))); 191 sal_Bool bReturn = sal_Bool(); 192 if ( a >>= bReturn ) 193 return bReturn; 194 } 195 } 196 catch ( css::uno::RuntimeException& ) 197 { 198 throw; 199 } 200 catch ( css::uno::Exception& ) 201 { 202 } 203 204 return sal_False; 205 } 206 207 SfxMailModel::SaveResult SfxMailModel::ShowFilterOptionsDialog( 208 uno::Reference< lang::XMultiServiceFactory > xSMGR, 209 uno::Reference< frame::XModel > xModel, 210 const rtl::OUString& rFilterName, 211 const rtl::OUString& rType, 212 bool bModified, 213 sal_Int32& rNumArgs, 214 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs ) 215 { 216 SaveResult eRet( SAVE_ERROR ); 217 218 try 219 { 220 uno::Sequence < beans::PropertyValue > aProps; 221 ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > xFilterCFG = 222 uno::Reference< container::XNameAccess >( 223 xSMGR->createInstance( 224 ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY ); 225 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY ); 226 227 if ( !xFilterCFG.is() ) 228 return eRet; 229 230 uno::Any aAny = xFilterCFG->getByName( rFilterName ); 231 232 if ( aAny >>= aProps ) 233 { 234 sal_Int32 nPropertyCount = aProps.getLength(); 235 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty ) 236 { 237 if( aProps[nProperty].Name.equals( ::rtl::OUString::createFromAscii( "UIComponent" )) ) 238 { 239 ::rtl::OUString aServiceName; 240 aProps[nProperty].Value >>= aServiceName; 241 if( aServiceName.getLength() ) 242 { 243 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog( 244 xSMGR->createInstance( aServiceName ), uno::UNO_QUERY ); 245 uno::Reference< beans::XPropertyAccess > xFilterProperties( 246 xFilterDialog, uno::UNO_QUERY ); 247 248 if( xFilterDialog.is() && xFilterProperties.is() ) 249 { 250 uno::Sequence< beans::PropertyValue > aPropsForDialog(1); 251 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY ); 252 253 if ( rType.equalsAsciiL( PDF_DOCUMENT_TYPE, PDF_DOCUMENT_TYPE_LEN )) 254 { 255 //add an internal property, used to tell the dialog we want to set a different 256 //string for the ok button 257 //used in filter/source/pdf/impdialog.cxx 258 String aOkSendText( SfxResId( STR_PDF_EXPORT_SEND )); 259 260 uno::Sequence< beans::PropertyValue > aFilterDataValue(1); 261 aFilterDataValue[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_OkButtonString" )); 262 aFilterDataValue[0].Value = css::uno::makeAny( ::rtl::OUString( aOkSendText )); 263 264 //add to the filterdata property, the only one the PDF export filter dialog will care for 265 aPropsForDialog[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterData" )); 266 aPropsForDialog[0].Value = css::uno::makeAny( aFilterDataValue ); 267 268 //when executing the dialog will merge the persistent FilterData properties 269 xFilterProperties->setPropertyValues( aPropsForDialog ); 270 } 271 272 if( xExporter.is() ) 273 xExporter->setSourceDocument( 274 uno::Reference< lang::XComponent >( xModel, uno::UNO_QUERY ) ); 275 276 if( xFilterDialog->execute() ) 277 { 278 //get the filter data 279 uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues(); 280 281 //add them to the args 282 for ( sal_Int32 nInd = 0; nInd < aPropsFromDialog.getLength(); nInd++ ) 283 { 284 if( aPropsFromDialog[ nInd ].Name.equals( ::rtl::OUString::createFromAscii( "FilterData" ) ) ) 285 { 286 //found the filterdata, add to the storing argument 287 rArgs.realloc( ++rNumArgs ); 288 rArgs[rNumArgs-1].Name = aPropsFromDialog[ nInd ].Name; 289 rArgs[rNumArgs-1].Value = aPropsFromDialog[ nInd ].Value; 290 break; 291 } 292 } 293 eRet = SAVE_SUCCESSFULL; 294 } 295 else 296 { 297 // cancel from dialog, then do not send 298 // If the model is not modified, it could be modified by the dispatch calls. 299 // Therefore set back to modified = false. This should not hurt if we call 300 // on a non-modified model. 301 if ( !bModified ) 302 { 303 try 304 { 305 xModifiable->setModified( sal_False ); 306 } 307 catch( com::sun::star::beans::PropertyVetoException& ) 308 { 309 } 310 } 311 eRet = SAVE_CANCELLED; 312 } 313 } 314 break; 315 } 316 } 317 } 318 } 319 } 320 catch( css::uno::RuntimeException& ) 321 { 322 throw; 323 } 324 catch( uno::Exception& ) 325 { 326 } 327 328 return eRet; 329 } 330 331 sal_Int32 SfxMailModel::GetCount() const 332 { 333 return maAttachedDocuments.size(); 334 } 335 336 sal_Bool SfxMailModel::IsEmpty() const 337 { 338 return maAttachedDocuments.empty(); 339 } 340 341 SfxMailModel::SaveResult SfxMailModel::SaveDocumentAsFormat( 342 const rtl::OUString& aSaveFileName, 343 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel, 344 const rtl::OUString& rType, 345 rtl::OUString& rFileNamePath ) 346 { 347 SaveResult eRet( SAVE_ERROR ); 348 bool bSendAsPDF = (rType.equalsAsciiL( PDF_DOCUMENT_TYPE, PDF_DOCUMENT_TYPE_LEN )); 349 350 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory(); 351 if (!xSMGR.is()) 352 return eRet; 353 354 const rtl::OUString aModuleManager( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.ModuleManager" )); 355 css::uno::Reference< css::frame::XModuleManager > xModuleManager( xSMGR->createInstance( aModuleManager ), css::uno::UNO_QUERY_THROW ); 356 if ( !xModuleManager.is() ) 357 return eRet; 358 359 rtl::OUString aModule; 360 try 361 { 362 aModule = xModuleManager->identify( xFrameOrModel ); 363 } 364 catch ( css::uno::RuntimeException& ) 365 { 366 throw; 367 } 368 catch ( css::uno::Exception& ) 369 { 370 } 371 372 css::uno::Reference< css::frame::XFrame > xFrame( xFrameOrModel, css::uno::UNO_QUERY ); 373 css::uno::Reference< css::frame::XModel > xModel( xFrameOrModel, css::uno::UNO_QUERY ); 374 if ( xFrame.is() ) 375 { 376 css::uno::Reference< css::frame::XController > xController = xFrame->getController(); 377 if ( xController.is() ) 378 xModel = xController->getModel(); 379 } 380 381 // We need at least a valid module name and model reference 382 if (( aModule.getLength() > 0 ) && xModel.is() ) 383 { 384 bool bModified( false ); 385 bool bHasLocation( false ); 386 bool bStoreTo( false ); 387 388 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY ); 389 css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY ); 390 391 if ( xModifiable.is() ) 392 bModified = xModifiable->isModified(); 393 if ( xStorable.is() ) 394 { 395 rtl::OUString aLocation = xStorable->getLocation(); 396 INetURLObject aFileObj( aLocation ); 397 398 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INET_PROT_PRIV_SOFFICE ); 399 400 bHasLocation = ( aLocation.getLength() > 0 ) && !bPrivateProtocol; 401 OSL_ASSERT( !bPrivateProtocol ); 402 } 403 if ( rType.getLength() > 0 ) 404 bStoreTo = true; 405 406 if ( xStorable.is() ) 407 { 408 rtl::OUString aFilterName; 409 rtl::OUString aTypeName( rType ); 410 rtl::OUString aFileName; 411 rtl::OUString aExtension; 412 413 css::uno::Reference< css::container::XContainerQuery > xContainerQuery( 414 xSMGR->createInstance( rtl::OUString( 415 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.FilterFactory" ))), 416 css::uno::UNO_QUERY ); 417 418 if ( bStoreTo ) 419 { 420 // Retrieve filter from type 421 css::uno::Sequence< css::beans::NamedValue > aQuery( bSendAsPDF ? 3 : 2 ); 422 aQuery[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type" )); 423 aQuery[0].Value = css::uno::makeAny( aTypeName ); 424 aQuery[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DocumentService" )); 425 aQuery[1].Value = css::uno::makeAny( aModule ); 426 if( bSendAsPDF ) 427 { 428 // #i91419# 429 // FIXME: we want just an export filter. However currently we need 430 // exact flag value as detailed in the filter configuration to get it 431 // this seems to be a bug 432 // without flags we get an import filter here, which is also unwanted 433 aQuery[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Flags" )); 434 aQuery[2].Value = css::uno::makeAny( sal_Int32(0x80042) ); // EXPORT ALIEN 3RDPARTY 435 } 436 437 css::uno::Reference< css::container::XEnumeration > xEnumeration = 438 xContainerQuery->createSubSetEnumerationByProperties( aQuery ); 439 440 if ( xEnumeration->hasMoreElements() ) 441 { 442 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() ); 443 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( 444 ::rtl::OUString::createFromAscii( "Name" ), 445 ::rtl::OUString() ); 446 } 447 448 if ( bHasLocation ) 449 { 450 // Retrieve filter from media descriptor 451 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() ); 452 rtl::OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault( 453 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" )), 454 ::rtl::OUString() ); 455 if ( aOrgFilterName == aFilterName ) 456 { 457 // We should save the document in the original format. Therefore this 458 // is not a storeTo operation. To support signing in this case, reset 459 // bStoreTo flag. 460 bStoreTo = false; 461 } 462 } 463 } 464 else 465 { 466 if ( bHasLocation ) 467 { 468 // Retrieve filter from media descriptor 469 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() ); 470 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault( 471 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" )), 472 ::rtl::OUString() ); 473 } 474 475 if ( !bHasLocation || ( aFilterName.getLength() == 0 )) 476 { 477 // Retrieve the user defined default filter 478 css::uno::Reference< css::container::XNameAccess > xNameAccess( xModuleManager, css::uno::UNO_QUERY ); 479 try 480 { 481 ::comphelper::SequenceAsHashMap aFilterPropsHM( xNameAccess->getByName( aModule ) ); 482 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( 483 ::rtl::OUString::createFromAscii( "ooSetupFactoryDefaultFilter" ), 484 ::rtl::OUString() ); 485 css::uno::Reference< css::container::XNameAccess > xNameAccess2( 486 xContainerQuery, css::uno::UNO_QUERY ); 487 if ( xNameAccess2.is() ) 488 { 489 ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess2->getByName( aFilterName ) ); 490 aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault( 491 ::rtl::OUString::createFromAscii( "Type" ), 492 ::rtl::OUString() ); 493 } 494 } 495 catch ( css::container::NoSuchElementException& ) 496 { 497 } 498 catch ( css::beans::UnknownPropertyException& ) 499 { 500 } 501 } 502 } 503 504 // No filter found => error 505 // No type and no location => error 506 if (( aFilterName.getLength() == 0 ) || 507 (( aTypeName.getLength() == 0 ) && !bHasLocation )) 508 return eRet; 509 510 // Determine filen name and extension 511 if ( bHasLocation && !bStoreTo ) 512 { 513 INetURLObject aFileObj( xStorable->getLocation() ); 514 aExtension = (rtl::OUString)aFileObj.getExtension(); 515 } 516 else 517 { 518 css::uno::Reference< container::XNameAccess > xTypeDetection( 519 xSMGR->createInstance( ::rtl::OUString( 520 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.TypeDetection" ))), 521 css::uno::UNO_QUERY ); 522 523 524 if ( xTypeDetection.is() ) 525 { 526 try 527 { 528 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( xTypeDetection->getByName( aTypeName ) ); 529 uno::Sequence< ::rtl::OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault( 530 ::rtl::OUString::createFromAscii( "Extensions" ), 531 ::uno::Sequence< ::rtl::OUString >() ); 532 if ( aExtensions.getLength() ) 533 aExtension = aExtensions[0]; 534 } 535 catch ( css::container::NoSuchElementException& ) 536 { 537 } 538 } 539 } 540 541 // Use provided save file name. If empty determine file name 542 aFileName = aSaveFileName; 543 if ( aFileName.getLength() == 0 ) 544 { 545 if ( !bHasLocation ) 546 { 547 // Create a noname file name with the correct extension 548 const rtl::OUString aNoNameFileName( RTL_CONSTASCII_USTRINGPARAM( "noname" )); 549 aFileName = aNoNameFileName; 550 } 551 else 552 { 553 // Determine file name from model 554 INetURLObject aFileObj( xStorable->getLocation() ); 555 aFileName = aFileObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::NO_DECODE ); 556 } 557 } 558 559 // No file name => error 560 if ( aFileName.getLength() == 0 ) 561 return eRet; 562 563 OSL_ASSERT( aFilterName.getLength() > 0 ); 564 OSL_ASSERT( aFileName.getLength() > 0 ); 565 566 // Creates a temporary directory to store a predefined file into it. 567 // This makes it possible to store the file for "send document as e-mail" 568 // with the original file name. We cannot use the original file as 569 // some mail programs need exclusive access. 570 ::utl::TempFile aTempDir( NULL, sal_True ); 571 572 INetURLObject aFilePathObj( aTempDir.GetURL() ); 573 aFilePathObj.insertName( aFileName ); 574 aFilePathObj.setExtension( aExtension ); 575 576 rtl::OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::NO_DECODE ); 577 578 sal_Int32 nNumArgs(0); 579 const rtl::OUString aPasswordPropName( RTL_CONSTASCII_USTRINGPARAM( "Password" )); 580 css::uno::Sequence< css::beans::PropertyValue > aArgs( ++nNumArgs ); 581 aArgs[nNumArgs-1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" )); 582 aArgs[nNumArgs-1].Value = css::uno::makeAny( aFilterName ); 583 584 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() ); 585 rtl::OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault( 586 aPasswordPropName, 587 ::rtl::OUString() ); 588 if ( aPassword.getLength() > 0 ) 589 { 590 aArgs.realloc( ++nNumArgs ); 591 aArgs[nNumArgs-1].Name = aPasswordPropName; 592 aArgs[nNumArgs-1].Value = css::uno::makeAny( aPassword ); 593 } 594 595 bool bNeedsPreparation = false; 596 css::util::URL aPrepareURL; 597 css::uno::Reference< css::frame::XDispatch > xPrepareDispatch; 598 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY ); 599 css::uno::Reference< css::util::XURLTransformer > xURLTransformer( 600 xSMGR->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))), 601 css::uno::UNO_QUERY ); 602 if( !bSendAsPDF ) 603 { 604 try 605 { 606 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content) 607 608 if ( xURLTransformer.is() ) 609 { 610 aPrepareURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:PrepareMailExport" )); 611 xURLTransformer->parseStrict( aPrepareURL ); 612 } 613 614 if ( xDispatchProvider.is() ) 615 { 616 xPrepareDispatch = css::uno::Reference< css::frame::XDispatch >( 617 xDispatchProvider->queryDispatch( aPrepareURL, ::rtl::OUString(), 0 )); 618 if ( xPrepareDispatch.is() ) 619 { 620 PrepareListener_Impl* pPrepareListener; 621 uno::Reference< css::frame::XStatusListener > xStatusListener = pPrepareListener = new PrepareListener_Impl; 622 xPrepareDispatch->addStatusListener( xStatusListener, aPrepareURL ); 623 bNeedsPreparation = pPrepareListener->IsSet(); 624 xPrepareDispatch->removeStatusListener( xStatusListener, aPrepareURL ); 625 } 626 } 627 } 628 catch ( css::uno::RuntimeException& ) 629 { 630 throw; 631 } 632 catch ( css::uno::Exception& ) 633 { 634 } 635 } 636 637 if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation ) 638 { 639 // Document is modified, is newly created or should be stored in a special format 640 try 641 { 642 if( bNeedsPreparation && xPrepareDispatch.is() ) 643 { 644 if ( xPrepareDispatch.is() ) 645 { 646 try 647 { 648 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs; 649 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs ); 650 } 651 catch ( css::uno::RuntimeException& ) 652 { 653 throw; 654 } 655 catch ( css::uno::Exception& ) 656 { 657 } 658 } 659 } 660 661 //check if this is the pdf otput filter (i#64555) 662 if( bSendAsPDF ) 663 { 664 SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog( 665 xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs ); 666 667 // don't continue on dialog cancel or error 668 if ( eShowPDFFilterDialog != SAVE_SUCCESSFULL ) 669 return eShowPDFFilterDialog; 670 } 671 672 xStorable->storeToURL( aFileURL, aArgs ); 673 rFileNamePath = aFileURL; 674 eRet = SAVE_SUCCESSFULL; 675 676 if( !bSendAsPDF ) 677 { 678 css::util::URL aURL; 679 // #i30432# notify that export is finished - the Writer may want to restore removed content 680 if ( xURLTransformer.is() ) 681 { 682 aURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:MailExportFinished" )); 683 xURLTransformer->parseStrict( aURL ); 684 } 685 686 if ( xDispatchProvider.is() ) 687 { 688 css::uno::Reference< css::frame::XDispatch > xDispatch = css::uno::Reference< css::frame::XDispatch >( 689 xDispatchProvider->queryDispatch( aURL, ::rtl::OUString(), 0 )); 690 if ( xDispatch.is() ) 691 { 692 try 693 { 694 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs; 695 xDispatch->dispatch( aURL, aDispatchArgs ); 696 } 697 catch ( css::uno::RuntimeException& ) 698 { 699 throw; 700 } 701 catch ( css::uno::Exception& ) 702 { 703 } 704 } 705 } 706 } 707 // If the model is not modified, it could be modified by the dispatch calls. 708 // Therefore set back to modified = false. This should not hurt if we call 709 // on a non-modified model. 710 if ( !bModified ) 711 { 712 try 713 { 714 xModifiable->setModified( sal_False ); 715 } 716 catch( com::sun::star::beans::PropertyVetoException& ) 717 { 718 } 719 } 720 } 721 catch ( com::sun::star::io::IOException& ) 722 { 723 eRet = SAVE_ERROR; 724 } 725 } 726 else 727 { 728 // We need 1:1 copy of the document to preserve an added signature. 729 aArgs.realloc( ++nNumArgs ); 730 aArgs[nNumArgs-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyStreamIfPossible" ) ); 731 aArgs[nNumArgs-1].Value = css::uno::makeAny( (sal_Bool)sal_True ); 732 733 try 734 { 735 xStorable->storeToURL( aFileURL, aArgs ); 736 rFileNamePath = aFileURL; 737 eRet = SAVE_SUCCESSFULL; 738 } 739 catch ( com::sun::star::io::IOException& ) 740 { 741 eRet = SAVE_ERROR; 742 } 743 } 744 } 745 } 746 747 return eRet; 748 } 749 750 SfxMailModel::SfxMailModel() : 751 mpToList ( NULL ), 752 mpCcList ( NULL ), 753 mpBccList ( NULL ), 754 mePriority ( PRIO_NORMAL ), 755 mbLoadDone ( sal_True ) 756 { 757 } 758 759 SfxMailModel::~SfxMailModel() 760 { 761 ClearList( mpToList ); 762 delete mpToList; 763 ClearList( mpCcList ); 764 delete mpCcList; 765 ClearList( mpBccList ); 766 delete mpBccList; 767 } 768 769 void SfxMailModel::AddAddress( const String& rAddress, AddressRole eRole ) 770 { 771 // don't add a empty address 772 if ( rAddress.Len() > 0 ) 773 { 774 AddressList_Impl* pList = NULL; 775 if ( ROLE_TO == eRole ) 776 { 777 if ( !mpToList ) 778 // create the list 779 mpToList = new AddressList_Impl; 780 pList = mpToList; 781 } 782 else if ( ROLE_CC == eRole ) 783 { 784 if ( !mpCcList ) 785 // create the list 786 mpCcList = new AddressList_Impl; 787 pList = mpCcList; 788 } 789 else if ( ROLE_BCC == eRole ) 790 { 791 if ( !mpBccList ) 792 // create the list 793 mpBccList = new AddressList_Impl; 794 pList = mpBccList; 795 } 796 else 797 { 798 DBG_ERRORFILE( "invalid address role" ); 799 } 800 801 if ( pList ) 802 { 803 // add address to list 804 AddressItemPtr_Impl pAddress = new String( rAddress ); 805 pList->Insert( pAddress, LIST_APPEND ); 806 } 807 } 808 } 809 810 SfxMailModel::SendMailResult SfxMailModel::AttachDocument( 811 const ::rtl::OUString& sDocumentType, 812 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel, 813 const ::rtl::OUString& sAttachmentTitle ) 814 { 815 rtl::OUString sFileName; 816 817 SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, sDocumentType, sFileName ); 818 if ( eSaveResult == SAVE_SUCCESSFULL && ( sFileName.getLength() > 0 ) ) 819 maAttachedDocuments.push_back(sFileName); 820 return eSaveResult == SAVE_SUCCESSFULL ? SEND_MAIL_OK : SEND_MAIL_ERROR; 821 } 822 823 SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame ) 824 { 825 OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!"); 826 SendMailResult eResult = SEND_MAIL_ERROR; 827 if ( !maAttachedDocuments.empty() ) 828 { 829 css::uno::Reference < XMultiServiceFactory > xMgr = ::comphelper::getProcessServiceFactory(); 830 if ( xMgr.is() ) 831 { 832 css::uno::Reference< XSimpleMailClientSupplier > xSimpleMailClientSupplier; 833 834 // Prefer the SimpleSystemMail service if available 835 xSimpleMailClientSupplier = css::uno::Reference< XSimpleMailClientSupplier >( 836 xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SimpleSystemMail" ))), 837 UNO_QUERY ); 838 839 if ( ! xSimpleMailClientSupplier.is() ) 840 { 841 xSimpleMailClientSupplier = css::uno::Reference< XSimpleMailClientSupplier >( 842 xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SimpleCommandMail" ))), 843 UNO_QUERY ); 844 } 845 846 if ( xSimpleMailClientSupplier.is() ) 847 { 848 css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient(); 849 850 if ( !xSimpleMailClient.is() ) 851 { 852 // no mail client support => message box! 853 return SEND_MAIL_ERROR; 854 } 855 856 // we have a simple mail client 857 css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage(); 858 if ( xSimpleMailMessage.is() ) 859 { 860 sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS; 861 if ( maFromAddress.Len() == 0 ) 862 { 863 // from address not set, try figure out users e-mail address 864 CreateFromAddress_Impl( maFromAddress ); 865 } 866 xSimpleMailMessage->setOriginator( maFromAddress ); 867 868 sal_Int32 nToCount = mpToList ? mpToList->Count() : 0; 869 sal_Int32 nCcCount = mpCcList ? mpCcList->Count() : 0; 870 sal_Int32 nCcSeqCount = nCcCount; 871 872 // set recipient (only one) for this simple mail server!! 873 if ( nToCount > 1 ) 874 { 875 nCcSeqCount = nToCount - 1 + nCcCount; 876 xSimpleMailMessage->setRecipient( *mpToList->GetObject( 0 )); 877 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE; 878 } 879 else if ( nToCount == 1 ) 880 { 881 xSimpleMailMessage->setRecipient( *mpToList->GetObject( 0 )); 882 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE; 883 } 884 885 // all other recipient must be handled with CC recipients! 886 if ( nCcSeqCount > 0 ) 887 { 888 sal_Int32 nIndex = 0; 889 Sequence< OUString > aCcRecipientSeq; 890 891 aCcRecipientSeq.realloc( nCcSeqCount ); 892 if ( nCcSeqCount > nCcCount ) 893 { 894 for ( sal_Int32 i = 1; i < nToCount; ++i ) 895 { 896 aCcRecipientSeq[nIndex++] = *mpToList->GetObject(i); 897 } 898 } 899 900 for ( sal_Int32 i = 0; i < nCcCount; i++ ) 901 { 902 aCcRecipientSeq[nIndex++] = *mpCcList->GetObject(i); 903 } 904 xSimpleMailMessage->setCcRecipient( aCcRecipientSeq ); 905 } 906 907 sal_Int32 nBccCount = mpBccList ? mpBccList->Count() : 0; 908 if ( nBccCount > 0 ) 909 { 910 Sequence< OUString > aBccRecipientSeq( nBccCount ); 911 for ( sal_Int32 i = 0; i < nBccCount; ++i ) 912 { 913 aBccRecipientSeq[i] = *mpBccList->GetObject(i); 914 } 915 xSimpleMailMessage->setBccRecipient( aBccRecipientSeq ); 916 } 917 918 Sequence< OUString > aAttachmentSeq(&(maAttachedDocuments[0]),maAttachedDocuments.size()); 919 920 xSimpleMailMessage->setSubject( maSubject ); 921 xSimpleMailMessage->setAttachement( aAttachmentSeq ); 922 923 sal_Bool bSend( sal_False ); 924 try 925 { 926 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags ); 927 bSend = sal_True; 928 } 929 catch ( IllegalArgumentException& ) 930 { 931 } 932 catch ( Exception& ) 933 { 934 } 935 936 if ( bSend == sal_False ) 937 { 938 css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow(); 939 940 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 941 Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow ); 942 943 ErrorBox aBox( pParentWindow, SfxResId( RID_ERRBOX_MAIL_CONFIG )); 944 aBox.Execute(); 945 eResult = SEND_MAIL_CANCELLED; 946 } 947 else 948 eResult = SEND_MAIL_OK; 949 } 950 } 951 } 952 } 953 else 954 eResult = SEND_MAIL_CANCELLED; 955 956 return eResult; 957 } 958 959 SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const rtl::OUString& rTypeName ) 960 { 961 SaveResult eSaveResult; 962 SendMailResult eResult = SEND_MAIL_ERROR; 963 rtl::OUString aFileName; 964 965 eSaveResult = SaveDocumentAsFormat( rtl::OUString(), xFrame, rTypeName, aFileName ); 966 967 if ( eSaveResult == SAVE_SUCCESSFULL ) 968 { 969 maAttachedDocuments.push_back( aFileName ); 970 return Send( xFrame ); 971 } 972 else if ( eSaveResult == SAVE_CANCELLED ) 973 eResult = SEND_MAIL_CANCELLED; 974 975 return eResult; 976 } 977 978 // functions ------------------------------------------------------------- 979 980 sal_Bool CreateFromAddress_Impl( String& rFrom ) 981 982 /* [Beschreibung] 983 984 Diese Funktion versucht mit Hilfe des IniManagers eine From-Adresse 985 zu erzeugen. daf"ur werden die Felder 'Vorname', 'Name' und 'EMail' 986 aus der Applikations-Ini-Datei ausgelesen. Sollten diese Felder 987 nicht gesetzt sein, wird FALSE zur"uckgegeben. 988 989 [R"uckgabewert] 990 991 sal_True: Adresse konnte erzeugt werden. 992 sal_False: Adresse konnte nicht erzeugt werden. 993 */ 994 995 { 996 SvtUserOptions aUserCFG; 997 String aName = aUserCFG.GetLastName (); 998 String aFirstName = aUserCFG.GetFirstName (); 999 if ( aFirstName.Len() || aName.Len() ) 1000 { 1001 if ( aFirstName.Len() ) 1002 { 1003 rFrom = TRIM( aFirstName ); 1004 1005 if ( aName.Len() ) 1006 rFrom += ' '; 1007 } 1008 rFrom += TRIM( aName ); 1009 // unerlaubte Zeichen entfernen 1010 rFrom.EraseAllChars( '<' ); 1011 rFrom.EraseAllChars( '>' ); 1012 rFrom.EraseAllChars( '@' ); 1013 } 1014 String aEmailName = aUserCFG.GetEmail(); 1015 1016 // unerlaubte Zeichen entfernen 1017 aEmailName.EraseAllChars( '<' ); 1018 aEmailName.EraseAllChars( '>' ); 1019 1020 if ( aEmailName.Len() ) 1021 { 1022 if ( rFrom.Len() ) 1023 rFrom += ' '; 1024 ( ( rFrom += '<' ) += TRIM( aEmailName ) ) += '>'; 1025 } 1026 else 1027 rFrom.Erase(); 1028 return ( rFrom.Len() > 0 ); 1029 } 1030