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