1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/PropertyValue.hpp>
21 #include <com/sun/star/beans/XPropertyAccess.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XContainerQuery.hpp>
24 #include <com/sun/star/document/XExporter.hpp>
25 #include <com/sun/star/embed/XStorage.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/embed/XTransactedObject.hpp>
28 #include <com/sun/star/frame/XDispatchProvider.hpp>
29 #include <com/sun/star/frame/XDispatch.hpp>
30 #include <com/sun/star/frame/XStatusListener.hpp>
31 #include <com/sun/star/frame/XFrame.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/ModuleManager.hpp>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/security/CertificateValidity.hpp>
37 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
38 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
39 #include <com/sun/star/system/SimpleSystemMail.hpp>
40 #include <com/sun/star/system/SimpleCommandMail.hpp>
41 #include <com/sun/star/system/XSimpleMailClientSupplier.hpp>
42 #include <com/sun/star/system/SimpleMailClientFlags.hpp>
43 #include <com/sun/star/ucb/CommandAbortedException.hpp>
44 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
45 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
46 #include <com/sun/star/uno/Reference.h>
47 #include <com/sun/star/util/URLTransformer.hpp>
48 #include <com/sun/star/util/XURLTransformer.hpp>
49 #include <com/sun/star/util/XModifiable.hpp>
50 #include <rtl/textenc.h>
52 #include <rtl/uri.hxx>
53 #include <rtl/ustrbuf.hxx>
54 #include <vcl/layout.hxx>
56 #include <sfx2/mailmodelapi.hxx>
57 #include "sfxtypes.hxx"
58 #include <sfx2/sfxresid.hxx>
59 #include <sfx2/sfxsids.hrc>
62 #include <unotools/tempfile.hxx>
63 #include <unotools/configitem.hxx>
64 #include <ucbhelper/content.hxx>
65 #include <tools/urlobj.hxx>
66 #include <unotools/useroptions.hxx>
67 #include <comphelper/extract.hxx>
68 #include <comphelper/processfactory.hxx>
69 #include <comphelper/sequenceashashmap.hxx>
70 #include <comphelper/storagehelper.hxx>
71 #include <comphelper/string.hxx>
72 #include <toolkit/helper/vclunohelper.hxx>
73 #include <vcl/svapp.hxx>
74 #include <cppuhelper/implbase1.hxx>
77 using namespace ::com::sun::star
;
78 using namespace ::com::sun::star::beans
;
79 using namespace ::com::sun::star::frame
;
80 using namespace ::com::sun::star::io
;
81 using namespace ::com::sun::star::lang
;
82 using namespace ::com::sun::star::ucb
;
83 using namespace ::com::sun::star::uno
;
84 using namespace ::com::sun::star::util
;
85 using namespace ::com::sun::star::system
;
87 // - class PrepareListener_Impl ------------------------------------------
88 class PrepareListener_Impl
: public ::cppu::WeakImplHelper1
< css::frame::XStatusListener
>
92 PrepareListener_Impl();
93 virtual ~PrepareListener_Impl();
95 // css.frame.XStatusListener
96 virtual void SAL_CALL
statusChanged(const css::frame::FeatureStateEvent
& aEvent
)
97 throw(css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
99 // css.lang.XEventListener
100 virtual void SAL_CALL
disposing(const css::lang::EventObject
& aEvent
)
101 throw(css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
103 bool IsSet() const {return m_bState
;}
106 PrepareListener_Impl::PrepareListener_Impl() :
111 PrepareListener_Impl::~PrepareListener_Impl()
115 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent
& rEvent
) throw(css::uno::RuntimeException
, std::exception
)
117 if( rEvent
.IsEnabled
)
118 rEvent
.State
>>= m_bState
;
123 void PrepareListener_Impl::disposing(const css::lang::EventObject
& /*rEvent*/) throw(css::uno::RuntimeException
, std::exception
)
127 // class SfxMailModel -----------------------------------------------
129 static const char PDF_DOCUMENT_TYPE
[] = "pdf_Portable_Document_Format";
131 SfxMailModel::SaveResult
SfxMailModel::ShowFilterOptionsDialog(
132 uno::Reference
< lang::XMultiServiceFactory
> xSMGR
,
133 uno::Reference
< frame::XModel
> xModel
,
134 const OUString
& rFilterName
,
135 const OUString
& rType
,
138 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
)
140 SaveResult
eRet( SAVE_ERROR
);
144 uno::Sequence
< beans::PropertyValue
> aProps
;
145 ::com::sun::star::uno::Reference
< ::com::sun::star::container::XNameAccess
> xFilterCFG
=
146 uno::Reference
< container::XNameAccess
>(
147 xSMGR
->createInstance(
148 OUString("com.sun.star.document.FilterFactory") ), uno::UNO_QUERY
);
149 css::uno::Reference
< css::util::XModifiable
> xModifiable( xModel
, css::uno::UNO_QUERY
);
151 if ( !xFilterCFG
.is() )
154 uno::Any aAny
= xFilterCFG
->getByName( rFilterName
);
156 if ( aAny
>>= aProps
)
158 sal_Int32 nPropertyCount
= aProps
.getLength();
159 for( sal_Int32 nProperty
=0; nProperty
< nPropertyCount
; ++nProperty
)
161 if( aProps
[nProperty
].Name
== "UIComponent" )
163 OUString aServiceName
;
164 aProps
[nProperty
].Value
>>= aServiceName
;
165 if( !aServiceName
.isEmpty() )
167 uno::Reference
< ui::dialogs::XExecutableDialog
> xFilterDialog(
168 xSMGR
->createInstance( aServiceName
), uno::UNO_QUERY
);
169 uno::Reference
< beans::XPropertyAccess
> xFilterProperties(
170 xFilterDialog
, uno::UNO_QUERY
);
172 if( xFilterDialog
.is() && xFilterProperties
.is() )
174 uno::Sequence
< beans::PropertyValue
> aPropsForDialog(1);
175 uno::Reference
< document::XExporter
> xExporter( xFilterDialog
, uno::UNO_QUERY
);
177 if ( rType
== PDF_DOCUMENT_TYPE
)
179 //add an internal property, used to tell the dialog we want to set a different
180 //string for the ok button
181 //used in filter/source/pdf/impdialog.cxx
182 uno::Sequence
< beans::PropertyValue
> aFilterDataValue(1);
183 aFilterDataValue
[0].Name
= "_OkButtonString";
184 aFilterDataValue
[0].Value
= css::uno::makeAny(SfxResId(STR_PDF_EXPORT_SEND
).toString());
186 //add to the filterdata property, the only one the PDF export filter dialog will care for
187 aPropsForDialog
[0].Name
= "FilterData";
188 aPropsForDialog
[0].Value
= css::uno::makeAny( aFilterDataValue
);
190 //when executing the dialog will merge the persistent FilterData properties
191 xFilterProperties
->setPropertyValues( aPropsForDialog
);
195 xExporter
->setSourceDocument(
196 uno::Reference
< lang::XComponent
>( xModel
, uno::UNO_QUERY
) );
198 if( xFilterDialog
->execute() )
200 //get the filter data
201 uno::Sequence
< beans::PropertyValue
> aPropsFromDialog
= xFilterProperties
->getPropertyValues();
203 //add them to the args
204 for ( sal_Int32 nInd
= 0; nInd
< aPropsFromDialog
.getLength(); nInd
++ )
206 if( aPropsFromDialog
[ nInd
].Name
== "FilterData" )
208 //found the filterdata, add to the storing argument
209 rArgs
.realloc( ++rNumArgs
);
210 rArgs
[rNumArgs
-1].Name
= aPropsFromDialog
[ nInd
].Name
;
211 rArgs
[rNumArgs
-1].Value
= aPropsFromDialog
[ nInd
].Value
;
215 eRet
= SAVE_SUCCESSFULL
;
219 // cancel from dialog, then do not send
220 // If the model is not modified, it could be modified by the dispatch calls.
221 // Therefore set back to modified = false. This should not hurt if we call
222 // on a non-modified model.
227 xModifiable
->setModified( sal_False
);
229 catch( com::sun::star::beans::PropertyVetoException
& )
233 eRet
= SAVE_CANCELLED
;
242 catch( css::uno::RuntimeException
& )
246 catch( uno::Exception
& )
253 bool SfxMailModel::IsEmpty() const
255 return maAttachedDocuments
.empty();
258 SfxMailModel::SaveResult
SfxMailModel::SaveDocumentAsFormat(
259 const OUString
& aSaveFileName
,
260 const css::uno::Reference
< css::uno::XInterface
>& xFrameOrModel
,
261 const OUString
& rType
,
262 OUString
& rFileNamePath
)
264 SaveResult
eRet( SAVE_ERROR
);
265 bool bSendAsPDF
= ( rType
== PDF_DOCUMENT_TYPE
);
267 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= ::comphelper::getProcessServiceFactory();
268 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
272 css::uno::Reference
< css::frame::XModuleManager2
> xModuleManager( css::frame::ModuleManager::create(xContext
) );
277 aModule
= xModuleManager
->identify( xFrameOrModel
);
279 catch ( css::uno::RuntimeException
& )
283 catch ( css::uno::Exception
& )
287 css::uno::Reference
< css::frame::XFrame
> xFrame( xFrameOrModel
, css::uno::UNO_QUERY
);
288 css::uno::Reference
< css::frame::XModel
> xModel( xFrameOrModel
, css::uno::UNO_QUERY
);
291 css::uno::Reference
< css::frame::XController
> xController
= xFrame
->getController();
292 if ( xController
.is() )
293 xModel
= xController
->getModel();
296 // We need at least a valid module name and model reference
297 if ( !aModule
.isEmpty() && xModel
.is() )
299 bool bModified( false );
300 bool bHasLocation( false );
301 bool bStoreTo( false );
303 css::uno::Reference
< css::util::XModifiable
> xModifiable( xModel
, css::uno::UNO_QUERY
);
304 css::uno::Reference
< css::frame::XStorable
> xStorable( xModel
, css::uno::UNO_QUERY
);
306 if ( xModifiable
.is() )
307 bModified
= xModifiable
->isModified();
308 if ( xStorable
.is() )
310 OUString aLocation
= xStorable
->getLocation();
311 INetURLObject
aFileObj( aLocation
);
313 bool bPrivateProtocol
= ( aFileObj
.GetProtocol() == INetProtocol::PrivSoffice
);
315 bHasLocation
= !aLocation
.isEmpty() && !bPrivateProtocol
;
316 OSL_ASSERT( !bPrivateProtocol
);
318 if ( !rType
.isEmpty() )
321 if ( xStorable
.is() )
323 OUString aFilterName
;
324 OUString
aTypeName( rType
);
328 css::uno::Reference
< css::container::XContainerQuery
> xContainerQuery(
329 xSMGR
->createInstance( OUString(
330 "com.sun.star.document.FilterFactory" )),
331 css::uno::UNO_QUERY
);
335 // Retrieve filter from type
336 css::uno::Sequence
< css::beans::NamedValue
> aQuery( bSendAsPDF
? 3 : 2 );
337 aQuery
[0].Name
= "Type";
338 aQuery
[0].Value
= css::uno::makeAny( aTypeName
);
339 aQuery
[1].Name
= "DocumentService";
340 aQuery
[1].Value
= css::uno::makeAny( aModule
);
344 // FIXME: we want just an export filter. However currently we need
345 // exact flag value as detailed in the filter configuration to get it
346 // this seems to be a bug
347 // without flags we get an import filter here, which is also unwanted
348 aQuery
[2].Name
= "Flags";
349 aQuery
[2].Value
= css::uno::makeAny( sal_Int32(0x80042) ); // EXPORT ALIEN 3RDPARTY
352 css::uno::Reference
< css::container::XEnumeration
> xEnumeration
=
353 xContainerQuery
->createSubSetEnumerationByProperties( aQuery
);
355 if ( xEnumeration
->hasMoreElements() )
357 ::comphelper::SequenceAsHashMap
aFilterPropsHM( xEnumeration
->nextElement() );
358 aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault(
365 // Retrieve filter from media descriptor
366 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
367 OUString aOrgFilterName
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
368 OUString( "FilterName" ),
370 if ( aOrgFilterName
== aFilterName
)
372 // We should save the document in the original format. Therefore this
373 // is not a storeTo operation. To support signing in this case, reset
383 // Retrieve filter from media descriptor
384 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
385 aFilterName
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
386 OUString( "FilterName" ),
390 if ( !bHasLocation
|| aFilterName
.isEmpty())
392 // Retrieve the user defined default filter
395 ::comphelper::SequenceAsHashMap
aFilterPropsHM( xModuleManager
->getByName( aModule
) );
396 aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault(
397 OUString("ooSetupFactoryDefaultFilter"),
399 css::uno::Reference
< css::container::XNameAccess
> xNameAccess(
400 xContainerQuery
, css::uno::UNO_QUERY
);
401 if ( xNameAccess
.is() )
403 ::comphelper::SequenceAsHashMap
aFilterPropsHM2( xNameAccess
->getByName( aFilterName
) );
404 aTypeName
= aFilterPropsHM2
.getUnpackedValueOrDefault(
409 catch ( css::container::NoSuchElementException
& )
412 catch ( css::beans::UnknownPropertyException
& )
418 // No filter found => error
419 // No type and no location => error
420 if (( aFilterName
.isEmpty() ) ||
421 ( aTypeName
.isEmpty() && !bHasLocation
))
424 // Determine file name and extension
425 if ( bHasLocation
&& !bStoreTo
)
427 INetURLObject
aFileObj( xStorable
->getLocation() );
428 aExtension
= aFileObj
.getExtension();
432 css::uno::Reference
< container::XNameAccess
> xTypeDetection(
433 xSMGR
->createInstance( OUString(
434 "com.sun.star.document.TypeDetection" )),
435 css::uno::UNO_QUERY
);
438 if ( xTypeDetection
.is() )
442 ::comphelper::SequenceAsHashMap
aTypeNamePropsHM( xTypeDetection
->getByName( aTypeName
) );
443 uno::Sequence
< OUString
> aExtensions
= aTypeNamePropsHM
.getUnpackedValueOrDefault(
444 OUString("Extensions"),
445 ::uno::Sequence
< OUString
>() );
446 if ( aExtensions
.getLength() )
447 aExtension
= aExtensions
[0];
449 catch ( css::container::NoSuchElementException
& )
455 // Use provided save file name. If empty determine file name
456 aFileName
= aSaveFileName
;
457 if ( aFileName
.isEmpty() )
461 // Create a noname file name with the correct extension
462 const OUString
aNoNameFileName( "noname" );
463 aFileName
= aNoNameFileName
;
467 // Determine file name from model
468 INetURLObject
aFileObj( xStorable
->getLocation() );
469 aFileName
= aFileObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::NO_DECODE
);
473 // No file name => error
474 if ( aFileName
.isEmpty() )
477 OSL_ASSERT( !aFilterName
.isEmpty() );
478 OSL_ASSERT( !aFileName
.isEmpty() );
480 // Creates a temporary directory to store a predefined file into it.
481 // This makes it possible to store the file for "send document as e-mail"
482 // with the original file name. We cannot use the original file as
483 // some mail programs need exclusive access.
484 ::utl::TempFile
aTempDir( NULL
, true );
486 INetURLObject
aFilePathObj( aTempDir
.GetURL() );
487 aFilePathObj
.insertName( aFileName
);
488 aFilePathObj
.setExtension( aExtension
);
490 OUString aFileURL
= aFilePathObj
.GetMainURL( INetURLObject::NO_DECODE
);
492 sal_Int32
nNumArgs(0);
493 const OUString
aPasswordPropName( "Password" );
494 css::uno::Sequence
< css::beans::PropertyValue
> aArgs( ++nNumArgs
);
495 aArgs
[nNumArgs
-1].Name
= "FilterName";
496 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( aFilterName
);
498 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
499 OUString aPassword
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
502 if ( !aPassword
.isEmpty() )
504 aArgs
.realloc( ++nNumArgs
);
505 aArgs
[nNumArgs
-1].Name
= aPasswordPropName
;
506 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( aPassword
);
509 bool bNeedsPreparation
= false;
510 css::util::URL aPrepareURL
;
511 css::uno::Reference
< css::frame::XDispatch
> xPrepareDispatch
;
512 css::uno::Reference
< css::frame::XDispatchProvider
> xDispatchProvider( xFrame
, css::uno::UNO_QUERY
);
513 css::uno::Reference
< css::util::XURLTransformer
> xURLTransformer( css::util::URLTransformer::create( xContext
) );
518 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
520 aPrepareURL
.Complete
= ".uno:PrepareMailExport";
521 xURLTransformer
->parseStrict( aPrepareURL
);
523 if ( xDispatchProvider
.is() )
525 xPrepareDispatch
= css::uno::Reference
< css::frame::XDispatch
>(
526 xDispatchProvider
->queryDispatch( aPrepareURL
, OUString(), 0 ));
527 if ( xPrepareDispatch
.is() )
529 PrepareListener_Impl
* pPrepareListener
;
530 uno::Reference
< css::frame::XStatusListener
> xStatusListener
= pPrepareListener
= new PrepareListener_Impl
;
531 xPrepareDispatch
->addStatusListener( xStatusListener
, aPrepareURL
);
532 bNeedsPreparation
= pPrepareListener
->IsSet();
533 xPrepareDispatch
->removeStatusListener( xStatusListener
, aPrepareURL
);
537 catch ( css::uno::RuntimeException
& )
541 catch ( css::uno::Exception
& )
546 if ( bModified
|| !bHasLocation
|| bStoreTo
|| bNeedsPreparation
)
548 // Document is modified, is newly created or should be stored in a special format
551 if( bNeedsPreparation
&& xPrepareDispatch
.is() )
553 if ( xPrepareDispatch
.is() )
557 css::uno::Sequence
< css::beans::PropertyValue
> aDispatchArgs
;
558 xPrepareDispatch
->dispatch( aPrepareURL
, aDispatchArgs
);
560 catch ( css::uno::RuntimeException
& )
564 catch ( css::uno::Exception
& )
570 //check if this is the pdf otput filter (i#64555)
573 SaveResult eShowPDFFilterDialog
= ShowFilterOptionsDialog(
574 xSMGR
, xModel
, aFilterName
, rType
, bModified
, nNumArgs
, aArgs
);
576 // don't continue on dialog cancel or error
577 if ( eShowPDFFilterDialog
!= SAVE_SUCCESSFULL
)
578 return eShowPDFFilterDialog
;
581 xStorable
->storeToURL( aFileURL
, aArgs
);
582 rFileNamePath
= aFileURL
;
583 eRet
= SAVE_SUCCESSFULL
;
588 // #i30432# notify that export is finished - the Writer may want to restore removed content
589 aURL
.Complete
= ".uno:MailExportFinished";
590 xURLTransformer
->parseStrict( aURL
);
592 if ( xDispatchProvider
.is() )
594 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= css::uno::Reference
< css::frame::XDispatch
>(
595 xDispatchProvider
->queryDispatch( aURL
, OUString(), 0 ));
596 if ( xDispatch
.is() )
600 css::uno::Sequence
< css::beans::PropertyValue
> aDispatchArgs
;
601 xDispatch
->dispatch( aURL
, aDispatchArgs
);
603 catch ( css::uno::RuntimeException
& )
607 catch ( css::uno::Exception
& )
613 // If the model is not modified, it could be modified by the dispatch calls.
614 // Therefore set back to modified = false. This should not hurt if we call
615 // on a non-modified model.
620 xModifiable
->setModified( sal_False
);
622 catch( com::sun::star::beans::PropertyVetoException
& )
627 catch ( com::sun::star::io::IOException
& )
634 // We need 1:1 copy of the document to preserve an added signature.
635 aArgs
.realloc( ++nNumArgs
);
636 aArgs
[nNumArgs
-1].Name
= "CopyStreamIfPossible";
637 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( true );
641 xStorable
->storeToURL( aFileURL
, aArgs
);
642 rFileNamePath
= aFileURL
;
643 eRet
= SAVE_SUCCESSFULL
;
645 catch ( com::sun::star::io::IOException
& )
656 SfxMailModel::SfxMailModel() :
660 mePriority ( PRIO_NORMAL
),
665 SfxMailModel::~SfxMailModel()
672 void SfxMailModel::AddAddress( const OUString
& rAddress
, AddressRole eRole
)
674 // don't add a empty address
675 if ( !rAddress
.isEmpty() )
677 AddressList_Impl
* pList
= NULL
;
678 if ( ROLE_TO
== eRole
)
682 mpToList
= new AddressList_Impl();
685 else if ( ROLE_CC
== eRole
)
689 mpCcList
= new AddressList_Impl();
692 else if ( ROLE_BCC
== eRole
)
696 mpBccList
= new AddressList_Impl();
701 SAL_WARN( "sfx.dialog", "invalid address role" );
706 // add address to list
707 pList
->push_back( rAddress
);
712 SfxMailModel::SendMailResult
SfxMailModel::AttachDocument(
713 const OUString
& sDocumentType
,
714 const css::uno::Reference
< css::uno::XInterface
>& xFrameOrModel
,
715 const OUString
& sAttachmentTitle
)
719 SaveResult eSaveResult
= SaveDocumentAsFormat( sAttachmentTitle
, xFrameOrModel
, sDocumentType
, sFileName
);
720 if ( eSaveResult
== SAVE_SUCCESSFULL
&& !sFileName
.isEmpty() )
721 maAttachedDocuments
.push_back(sFileName
);
722 return eSaveResult
== SAVE_SUCCESSFULL
? SEND_MAIL_OK
: SEND_MAIL_ERROR
;
725 SfxMailModel::SendMailResult
SfxMailModel::Send( const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
727 OSL_ENSURE(!maAttachedDocuments
.empty(),"No document added!");
728 SendMailResult eResult
= SEND_MAIL_ERROR
;
729 if ( !maAttachedDocuments
.empty() )
731 css::uno::Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
733 css::uno::Reference
< XSimpleMailClientSupplier
> xSimpleMailClientSupplier
;
735 // Prefer the SimpleSystemMail service if available
737 xSimpleMailClientSupplier
= SimpleSystemMail::create( xContext
);
739 catch ( const uno::Exception
& )
742 if ( ! xSimpleMailClientSupplier
.is() )
745 xSimpleMailClientSupplier
= SimpleCommandMail::create( xContext
);
747 catch ( const uno::Exception
& )
751 if ( xSimpleMailClientSupplier
.is() )
753 css::uno::Reference
< XSimpleMailClient
> xSimpleMailClient
= xSimpleMailClientSupplier
->querySimpleMailClient();
755 if ( !xSimpleMailClient
.is() )
757 // no mail client support => message box!
758 return SEND_MAIL_ERROR
;
761 // we have a simple mail client
762 css::uno::Reference
< XSimpleMailMessage
> xSimpleMailMessage
= xSimpleMailClient
->createSimpleMailMessage();
763 if ( xSimpleMailMessage
.is() )
765 sal_Int32 nSendFlags
= SimpleMailClientFlags::DEFAULTS
;
766 if ( maFromAddress
.isEmpty() )
768 // from address not set, try figure out users e-mail address
769 CreateFromAddress_Impl( maFromAddress
);
771 xSimpleMailMessage
->setOriginator( maFromAddress
);
773 size_t nToCount
= mpToList
? mpToList
->size() : 0;
774 size_t nCcCount
= mpCcList
? mpCcList
->size() : 0;
775 size_t nCcSeqCount
= nCcCount
;
777 // set recipient (only one) for this simple mail server!!
780 nCcSeqCount
= nToCount
- 1 + nCcCount
;
781 xSimpleMailMessage
->setRecipient( mpToList
->at( 0 ) );
782 nSendFlags
= SimpleMailClientFlags::NO_USER_INTERFACE
;
784 else if ( nToCount
== 1 )
786 xSimpleMailMessage
->setRecipient( mpToList
->at( 0 ) );
787 nSendFlags
= SimpleMailClientFlags::NO_USER_INTERFACE
;
790 // all other recipient must be handled with CC recipients!
791 if ( nCcSeqCount
> 0 )
794 Sequence
< OUString
> aCcRecipientSeq
;
796 aCcRecipientSeq
.realloc( nCcSeqCount
);
797 if ( nCcSeqCount
> nCcCount
)
799 for ( size_t i
= 1; i
< nToCount
; ++i
)
801 aCcRecipientSeq
[nIndex
++] = mpToList
->at(i
);
805 for ( size_t i
= 0; i
< nCcCount
; i
++ )
807 aCcRecipientSeq
[nIndex
++] = mpCcList
->at(i
);
809 xSimpleMailMessage
->setCcRecipient( aCcRecipientSeq
);
812 size_t nBccCount
= mpBccList
? mpBccList
->size() : 0;
815 Sequence
< OUString
> aBccRecipientSeq( nBccCount
);
816 for ( size_t i
= 0; i
< nBccCount
; ++i
)
818 aBccRecipientSeq
[i
] = mpBccList
->at(i
);
820 xSimpleMailMessage
->setBccRecipient( aBccRecipientSeq
);
823 Sequence
< OUString
> aAttachmentSeq(&(maAttachedDocuments
[0]),maAttachedDocuments
.size());
825 if ( xSimpleMailMessage
->getSubject().isEmpty() ) {
827 maAttachedDocuments
[0], INetURLObject::WAS_ENCODED
);
830 INetURLObject::LAST_SEGMENT
, false,
832 INetURLObject::NO_DECODE
)); // MAPISendMail does not accept Unicode
834 INetURLObject::DECODE_WITH_CHARSET
));
836 if (subject
.isEmpty()) {
837 subject
= maAttachedDocuments
[0];
839 if ( maAttachedDocuments
.size() > 1 )
841 xSimpleMailMessage
->setSubject( subject
);
843 xSimpleMailMessage
->setAttachement( aAttachmentSeq
);
848 xSimpleMailClient
->sendSimpleMailMessage( xSimpleMailMessage
, nSendFlags
);
851 catch ( IllegalArgumentException
& )
860 css::uno::Reference
< css::awt::XWindow
> xParentWindow
= xFrame
->getContainerWindow();
862 SolarMutexGuard aGuard
;
863 vcl::Window
* pParentWindow
= VCLUnoHelper::GetWindow( xParentWindow
);
865 ScopedVclPtrInstance
< MessageDialog
> aBox(pParentWindow
, "ErrorFindEmailDialog", "sfx/ui/errorfindemaildialog.ui");
867 eResult
= SEND_MAIL_CANCELLED
;
870 eResult
= SEND_MAIL_OK
;
875 eResult
= SEND_MAIL_CANCELLED
;
880 SfxMailModel::SendMailResult
SfxMailModel::SaveAndSend( const css::uno::Reference
< css::frame::XFrame
>& xFrame
, const OUString
& rTypeName
)
882 SaveResult eSaveResult
;
883 SendMailResult eResult
= SEND_MAIL_ERROR
;
886 eSaveResult
= SaveDocumentAsFormat( OUString(), xFrame
, rTypeName
, aFileName
);
888 if ( eSaveResult
== SAVE_SUCCESSFULL
)
890 maAttachedDocuments
.push_back( aFileName
);
891 return Send( xFrame
);
893 else if ( eSaveResult
== SAVE_CANCELLED
)
894 eResult
= SEND_MAIL_CANCELLED
;
899 // functions -------------------------------------------------------------
901 bool CreateFromAddress_Impl( OUString
& rFrom
)
905 This function tries to create a From-address with the help of IniManagers.
906 For this the fields 'first name', 'Name' and 'Email' are read from the
907 application-ini-data. If these fields are not set, FALSE is returned.
911 sal_True: Address could be created.
912 sal_False: Address could not be created.
916 SvtUserOptions aUserCFG
;
917 OUString aName
= aUserCFG
.GetLastName ();
918 OUString aFirstName
= aUserCFG
.GetFirstName ();
919 if ( !aFirstName
.isEmpty() || !aName
.isEmpty() )
921 if ( !aFirstName
.isEmpty() )
923 rFrom
= comphelper::string::strip(aFirstName
, ' ');
925 if ( !aName
.isEmpty() )
928 rFrom
+= comphelper::string::strip(aName
, ' ');
929 // remove illegal characters
930 rFrom
= comphelper::string::remove(rFrom
, '<');
931 rFrom
= comphelper::string::remove(rFrom
, '>');
932 rFrom
= comphelper::string::remove(rFrom
, '@');
934 OUString aEmailName
= aUserCFG
.GetEmail();
936 // remove illegal characters
937 aEmailName
= comphelper::string::remove(aEmailName
, '<');
938 aEmailName
= comphelper::string::remove(aEmailName
, '>');
940 if ( !aEmailName
.isEmpty() )
942 if ( !rFrom
.isEmpty() )
944 rFrom
= rFrom
+ "<" + comphelper::string::strip(aEmailName
, ' ') + ">";
948 return !rFrom
.isEmpty();
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */