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