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/msgbox.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/mediadescriptor.hxx>
69 #include <comphelper/processfactory.hxx>
70 #include <comphelper/sequenceashashmap.hxx>
71 #include <comphelper/sequenceasvector.hxx>
72 #include <comphelper/storagehelper.hxx>
73 #include <comphelper/string.hxx>
74 #include <toolkit/helper/vclunohelper.hxx>
75 #include <vcl/svapp.hxx>
76 #include <cppuhelper/implbase1.hxx>
78 // --------------------------------------------------------------
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::beans
;
81 using namespace ::com::sun::star::frame
;
82 using namespace ::com::sun::star::io
;
83 using namespace ::com::sun::star::lang
;
84 using namespace ::com::sun::star::ucb
;
85 using namespace ::com::sun::star::uno
;
86 using namespace ::com::sun::star::util
;
87 using namespace ::com::sun::star::system
;
88 using namespace ::rtl
;
90 // - class PrepareListener_Impl ------------------------------------------
91 class PrepareListener_Impl
: public ::cppu::WeakImplHelper1
< css::frame::XStatusListener
>
95 PrepareListener_Impl();
96 virtual ~PrepareListener_Impl();
98 // css.frame.XStatusListener
99 virtual void SAL_CALL
statusChanged(const css::frame::FeatureStateEvent
& aEvent
)
100 throw(css::uno::RuntimeException
);
102 // css.lang.XEventListener
103 virtual void SAL_CALL
disposing(const css::lang::EventObject
& aEvent
)
104 throw(css::uno::RuntimeException
);
106 bool IsSet() const {return m_bState
;}
109 PrepareListener_Impl::PrepareListener_Impl() :
114 PrepareListener_Impl::~PrepareListener_Impl()
118 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent
& rEvent
) throw(css::uno::RuntimeException
)
120 if( rEvent
.IsEnabled
)
121 rEvent
.State
>>= m_bState
;
123 m_bState
= sal_False
;
126 void PrepareListener_Impl::disposing(const css::lang::EventObject
& /*rEvent*/) throw(css::uno::RuntimeException
)
130 // class SfxMailModel -----------------------------------------------
132 static const char PDF_DOCUMENT_TYPE
[] = "pdf_Portable_Document_Format";
134 void SfxMailModel::ClearList( AddressList_Impl
* pList
)
138 for( size_t i
= 0, n
= pList
->size(); i
< n
; ++i
)
144 sal_Bool
HasDocumentValidSignature( const css::uno::Reference
< css::frame::XModel
>& xModel
)
148 css::uno::Reference
< css::beans::XPropertySet
> xPropSet( xModel
, css::uno::UNO_QUERY
);
151 Any a
= xPropSet
->getPropertyValue( OUString( "HasValidSignatures" ));
152 sal_Bool bReturn
= sal_Bool();
157 catch ( css::uno::RuntimeException
& )
161 catch ( css::uno::Exception
& )
168 SfxMailModel::SaveResult
SfxMailModel::ShowFilterOptionsDialog(
169 uno::Reference
< lang::XMultiServiceFactory
> xSMGR
,
170 uno::Reference
< frame::XModel
> xModel
,
171 const OUString
& rFilterName
,
172 const OUString
& rType
,
175 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
>& rArgs
)
177 SaveResult
eRet( SAVE_ERROR
);
181 uno::Sequence
< beans::PropertyValue
> aProps
;
182 ::com::sun::star::uno::Reference
< ::com::sun::star::container::XNameAccess
> xFilterCFG
=
183 uno::Reference
< container::XNameAccess
>(
184 xSMGR
->createInstance(
185 OUString("com.sun.star.document.FilterFactory") ), uno::UNO_QUERY
);
186 css::uno::Reference
< css::util::XModifiable
> xModifiable( xModel
, css::uno::UNO_QUERY
);
188 if ( !xFilterCFG
.is() )
191 uno::Any aAny
= xFilterCFG
->getByName( rFilterName
);
193 if ( aAny
>>= aProps
)
195 sal_Int32 nPropertyCount
= aProps
.getLength();
196 for( sal_Int32 nProperty
=0; nProperty
< nPropertyCount
; ++nProperty
)
198 if( aProps
[nProperty
].Name
== "UIComponent" )
200 OUString aServiceName
;
201 aProps
[nProperty
].Value
>>= aServiceName
;
202 if( !aServiceName
.isEmpty() )
204 uno::Reference
< ui::dialogs::XExecutableDialog
> xFilterDialog(
205 xSMGR
->createInstance( aServiceName
), uno::UNO_QUERY
);
206 uno::Reference
< beans::XPropertyAccess
> xFilterProperties(
207 xFilterDialog
, uno::UNO_QUERY
);
209 if( xFilterDialog
.is() && xFilterProperties
.is() )
211 uno::Sequence
< beans::PropertyValue
> aPropsForDialog(1);
212 uno::Reference
< document::XExporter
> xExporter( xFilterDialog
, uno::UNO_QUERY
);
214 if ( rType
== PDF_DOCUMENT_TYPE
)
216 //add an internal property, used to tell the dialog we want to set a different
217 //string for the ok button
218 //used in filter/source/pdf/impdialog.cxx
219 uno::Sequence
< beans::PropertyValue
> aFilterDataValue(1);
220 aFilterDataValue
[0].Name
= OUString( "_OkButtonString" );
221 aFilterDataValue
[0].Value
= css::uno::makeAny(SfxResId(STR_PDF_EXPORT_SEND
).toString());
223 //add to the filterdata property, the only one the PDF export filter dialog will care for
224 aPropsForDialog
[0].Name
= OUString( "FilterData" );
225 aPropsForDialog
[0].Value
= css::uno::makeAny( aFilterDataValue
);
227 //when executing the dialog will merge the persistent FilterData properties
228 xFilterProperties
->setPropertyValues( aPropsForDialog
);
232 xExporter
->setSourceDocument(
233 uno::Reference
< lang::XComponent
>( xModel
, uno::UNO_QUERY
) );
235 if( xFilterDialog
->execute() )
237 //get the filter data
238 uno::Sequence
< beans::PropertyValue
> aPropsFromDialog
= xFilterProperties
->getPropertyValues();
240 //add them to the args
241 for ( sal_Int32 nInd
= 0; nInd
< aPropsFromDialog
.getLength(); nInd
++ )
243 if( aPropsFromDialog
[ nInd
].Name
== "FilterData" )
245 //found the filterdata, add to the storing argument
246 rArgs
.realloc( ++rNumArgs
);
247 rArgs
[rNumArgs
-1].Name
= aPropsFromDialog
[ nInd
].Name
;
248 rArgs
[rNumArgs
-1].Value
= aPropsFromDialog
[ nInd
].Value
;
252 eRet
= SAVE_SUCCESSFULL
;
256 // cancel from dialog, then do not send
257 // If the model is not modified, it could be modified by the dispatch calls.
258 // Therefore set back to modified = false. This should not hurt if we call
259 // on a non-modified model.
264 xModifiable
->setModified( sal_False
);
266 catch( com::sun::star::beans::PropertyVetoException
& )
270 eRet
= SAVE_CANCELLED
;
279 catch( css::uno::RuntimeException
& )
283 catch( uno::Exception
& )
290 sal_Bool
SfxMailModel::IsEmpty() const
292 return maAttachedDocuments
.empty();
295 SfxMailModel::SaveResult
SfxMailModel::SaveDocumentAsFormat(
296 const OUString
& aSaveFileName
,
297 const css::uno::Reference
< css::uno::XInterface
>& xFrameOrModel
,
298 const OUString
& rType
,
299 OUString
& rFileNamePath
)
301 SaveResult
eRet( SAVE_ERROR
);
302 bool bSendAsPDF
= ( rType
== PDF_DOCUMENT_TYPE
);
304 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= ::comphelper::getProcessServiceFactory();
305 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
309 css::uno::Reference
< css::frame::XModuleManager2
> xModuleManager( css::frame::ModuleManager::create(xContext
) );
314 aModule
= xModuleManager
->identify( xFrameOrModel
);
316 catch ( css::uno::RuntimeException
& )
320 catch ( css::uno::Exception
& )
324 css::uno::Reference
< css::frame::XFrame
> xFrame( xFrameOrModel
, css::uno::UNO_QUERY
);
325 css::uno::Reference
< css::frame::XModel
> xModel( xFrameOrModel
, css::uno::UNO_QUERY
);
328 css::uno::Reference
< css::frame::XController
> xController
= xFrame
->getController();
329 if ( xController
.is() )
330 xModel
= xController
->getModel();
333 // We need at least a valid module name and model reference
334 if ( !aModule
.isEmpty() && xModel
.is() )
336 bool bModified( false );
337 bool bHasLocation( false );
338 bool bStoreTo( false );
340 css::uno::Reference
< css::util::XModifiable
> xModifiable( xModel
, css::uno::UNO_QUERY
);
341 css::uno::Reference
< css::frame::XStorable
> xStorable( xModel
, css::uno::UNO_QUERY
);
343 if ( xModifiable
.is() )
344 bModified
= xModifiable
->isModified();
345 if ( xStorable
.is() )
347 OUString aLocation
= xStorable
->getLocation();
348 INetURLObject
aFileObj( aLocation
);
350 bool bPrivateProtocol
= ( aFileObj
.GetProtocol() == INET_PROT_PRIV_SOFFICE
);
352 bHasLocation
= !aLocation
.isEmpty() && !bPrivateProtocol
;
353 OSL_ASSERT( !bPrivateProtocol
);
355 if ( !rType
.isEmpty() )
358 if ( xStorable
.is() )
360 OUString aFilterName
;
361 OUString
aTypeName( rType
);
365 css::uno::Reference
< css::container::XContainerQuery
> xContainerQuery(
366 xSMGR
->createInstance( OUString(
367 "com.sun.star.document.FilterFactory" )),
368 css::uno::UNO_QUERY
);
372 // Retrieve filter from type
373 css::uno::Sequence
< css::beans::NamedValue
> aQuery( bSendAsPDF
? 3 : 2 );
374 aQuery
[0].Name
= OUString( "Type" );
375 aQuery
[0].Value
= css::uno::makeAny( aTypeName
);
376 aQuery
[1].Name
= OUString( "DocumentService" );
377 aQuery
[1].Value
= css::uno::makeAny( aModule
);
381 // FIXME: we want just an export filter. However currently we need
382 // exact flag value as detailed in the filter configuration to get it
383 // this seems to be a bug
384 // without flags we get an import filter here, which is also unwanted
385 aQuery
[2].Name
= OUString( "Flags" );
386 aQuery
[2].Value
= css::uno::makeAny( sal_Int32(0x80042) ); // EXPORT ALIEN 3RDPARTY
389 css::uno::Reference
< css::container::XEnumeration
> xEnumeration
=
390 xContainerQuery
->createSubSetEnumerationByProperties( aQuery
);
392 if ( xEnumeration
->hasMoreElements() )
394 ::comphelper::SequenceAsHashMap
aFilterPropsHM( xEnumeration
->nextElement() );
395 aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault(
402 // Retrieve filter from media descriptor
403 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
404 OUString aOrgFilterName
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
405 OUString( "FilterName" ),
407 if ( aOrgFilterName
== aFilterName
)
409 // We should save the document in the original format. Therefore this
410 // is not a storeTo operation. To support signing in this case, reset
420 // Retrieve filter from media descriptor
421 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
422 aFilterName
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
423 OUString( "FilterName" ),
427 if ( !bHasLocation
|| aFilterName
.isEmpty())
429 // Retrieve the user defined default filter
432 ::comphelper::SequenceAsHashMap
aFilterPropsHM( xModuleManager
->getByName( aModule
) );
433 aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault(
434 OUString("ooSetupFactoryDefaultFilter"),
436 css::uno::Reference
< css::container::XNameAccess
> xNameAccess(
437 xContainerQuery
, css::uno::UNO_QUERY
);
438 if ( xNameAccess
.is() )
440 ::comphelper::SequenceAsHashMap
aFilterPropsHM2( xNameAccess
->getByName( aFilterName
) );
441 aTypeName
= aFilterPropsHM2
.getUnpackedValueOrDefault(
446 catch ( css::container::NoSuchElementException
& )
449 catch ( css::beans::UnknownPropertyException
& )
455 // No filter found => error
456 // No type and no location => error
457 if (( aFilterName
.isEmpty() ) ||
458 ( aTypeName
.isEmpty() && !bHasLocation
))
461 // Determine filen name and extension
462 if ( bHasLocation
&& !bStoreTo
)
464 INetURLObject
aFileObj( xStorable
->getLocation() );
465 aExtension
= (OUString
)aFileObj
.getExtension();
469 css::uno::Reference
< container::XNameAccess
> xTypeDetection(
470 xSMGR
->createInstance( OUString(
471 "com.sun.star.document.TypeDetection" )),
472 css::uno::UNO_QUERY
);
475 if ( xTypeDetection
.is() )
479 ::comphelper::SequenceAsHashMap
aTypeNamePropsHM( xTypeDetection
->getByName( aTypeName
) );
480 uno::Sequence
< OUString
> aExtensions
= aTypeNamePropsHM
.getUnpackedValueOrDefault(
481 OUString("Extensions"),
482 ::uno::Sequence
< OUString
>() );
483 if ( aExtensions
.getLength() )
484 aExtension
= aExtensions
[0];
486 catch ( css::container::NoSuchElementException
& )
492 // Use provided save file name. If empty determine file name
493 aFileName
= aSaveFileName
;
494 if ( aFileName
.isEmpty() )
498 // Create a noname file name with the correct extension
499 const OUString
aNoNameFileName( "noname" );
500 aFileName
= aNoNameFileName
;
504 // Determine file name from model
505 INetURLObject
aFileObj( xStorable
->getLocation() );
506 aFileName
= aFileObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::NO_DECODE
);
510 // No file name => error
511 if ( aFileName
.isEmpty() )
514 OSL_ASSERT( !aFilterName
.isEmpty() );
515 OSL_ASSERT( !aFileName
.isEmpty() );
517 // Creates a temporary directory to store a predefined file into it.
518 // This makes it possible to store the file for "send document as e-mail"
519 // with the original file name. We cannot use the original file as
520 // some mail programs need exclusive access.
521 ::utl::TempFile
aTempDir( NULL
, sal_True
);
523 INetURLObject
aFilePathObj( aTempDir
.GetURL() );
524 aFilePathObj
.insertName( aFileName
);
525 aFilePathObj
.setExtension( aExtension
);
527 OUString aFileURL
= aFilePathObj
.GetMainURL( INetURLObject::NO_DECODE
);
529 sal_Int32
nNumArgs(0);
530 const OUString
aPasswordPropName( "Password" );
531 css::uno::Sequence
< css::beans::PropertyValue
> aArgs( ++nNumArgs
);
532 aArgs
[nNumArgs
-1].Name
= OUString( "FilterName" );
533 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( aFilterName
);
535 ::comphelper::SequenceAsHashMap
aMediaDescrPropsHM( xModel
->getArgs() );
536 OUString aPassword
= aMediaDescrPropsHM
.getUnpackedValueOrDefault(
539 if ( !aPassword
.isEmpty() )
541 aArgs
.realloc( ++nNumArgs
);
542 aArgs
[nNumArgs
-1].Name
= aPasswordPropName
;
543 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( aPassword
);
546 bool bNeedsPreparation
= false;
547 css::util::URL aPrepareURL
;
548 css::uno::Reference
< css::frame::XDispatch
> xPrepareDispatch
;
549 css::uno::Reference
< css::frame::XDispatchProvider
> xDispatchProvider( xFrame
, css::uno::UNO_QUERY
);
550 css::uno::Reference
< css::util::XURLTransformer
> xURLTransformer( css::util::URLTransformer::create( xContext
) );
555 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
557 aPrepareURL
.Complete
= OUString( ".uno:PrepareMailExport" );
558 xURLTransformer
->parseStrict( aPrepareURL
);
560 if ( xDispatchProvider
.is() )
562 xPrepareDispatch
= css::uno::Reference
< css::frame::XDispatch
>(
563 xDispatchProvider
->queryDispatch( aPrepareURL
, OUString(), 0 ));
564 if ( xPrepareDispatch
.is() )
566 PrepareListener_Impl
* pPrepareListener
;
567 uno::Reference
< css::frame::XStatusListener
> xStatusListener
= pPrepareListener
= new PrepareListener_Impl
;
568 xPrepareDispatch
->addStatusListener( xStatusListener
, aPrepareURL
);
569 bNeedsPreparation
= pPrepareListener
->IsSet();
570 xPrepareDispatch
->removeStatusListener( xStatusListener
, aPrepareURL
);
574 catch ( css::uno::RuntimeException
& )
578 catch ( css::uno::Exception
& )
583 if ( bModified
|| !bHasLocation
|| bStoreTo
|| bNeedsPreparation
)
585 // Document is modified, is newly created or should be stored in a special format
588 if( bNeedsPreparation
&& xPrepareDispatch
.is() )
590 if ( xPrepareDispatch
.is() )
594 css::uno::Sequence
< css::beans::PropertyValue
> aDispatchArgs
;
595 xPrepareDispatch
->dispatch( aPrepareURL
, aDispatchArgs
);
597 catch ( css::uno::RuntimeException
& )
601 catch ( css::uno::Exception
& )
607 //check if this is the pdf otput filter (i#64555)
610 SaveResult eShowPDFFilterDialog
= ShowFilterOptionsDialog(
611 xSMGR
, xModel
, aFilterName
, rType
, bModified
, nNumArgs
, aArgs
);
613 // don't continue on dialog cancel or error
614 if ( eShowPDFFilterDialog
!= SAVE_SUCCESSFULL
)
615 return eShowPDFFilterDialog
;
618 xStorable
->storeToURL( aFileURL
, aArgs
);
619 rFileNamePath
= aFileURL
;
620 eRet
= SAVE_SUCCESSFULL
;
625 // #i30432# notify that export is finished - the Writer may want to restore removed content
626 aURL
.Complete
= OUString( ".uno:MailExportFinished" );
627 xURLTransformer
->parseStrict( aURL
);
629 if ( xDispatchProvider
.is() )
631 css::uno::Reference
< css::frame::XDispatch
> xDispatch
= css::uno::Reference
< css::frame::XDispatch
>(
632 xDispatchProvider
->queryDispatch( aURL
, OUString(), 0 ));
633 if ( xDispatch
.is() )
637 css::uno::Sequence
< css::beans::PropertyValue
> aDispatchArgs
;
638 xDispatch
->dispatch( aURL
, aDispatchArgs
);
640 catch ( css::uno::RuntimeException
& )
644 catch ( css::uno::Exception
& )
650 // If the model is not modified, it could be modified by the dispatch calls.
651 // Therefore set back to modified = false. This should not hurt if we call
652 // on a non-modified model.
657 xModifiable
->setModified( sal_False
);
659 catch( com::sun::star::beans::PropertyVetoException
& )
664 catch ( com::sun::star::io::IOException
& )
671 // We need 1:1 copy of the document to preserve an added signature.
672 aArgs
.realloc( ++nNumArgs
);
673 aArgs
[nNumArgs
-1].Name
= OUString( "CopyStreamIfPossible" );
674 aArgs
[nNumArgs
-1].Value
= css::uno::makeAny( (sal_Bool
)sal_True
);
678 xStorable
->storeToURL( aFileURL
, aArgs
);
679 rFileNamePath
= aFileURL
;
680 eRet
= SAVE_SUCCESSFULL
;
682 catch ( com::sun::star::io::IOException
& )
693 SfxMailModel::SfxMailModel() :
697 mePriority ( PRIO_NORMAL
),
698 mbLoadDone ( sal_True
)
702 SfxMailModel::~SfxMailModel()
704 ClearList( mpToList
);
706 ClearList( mpCcList
);
708 ClearList( mpBccList
);
712 void SfxMailModel::AddAddress( const String
& rAddress
, AddressRole eRole
)
714 // don't add a empty address
715 if ( rAddress
.Len() > 0 )
717 AddressList_Impl
* pList
= NULL
;
718 if ( ROLE_TO
== eRole
)
722 mpToList
= new AddressList_Impl();
725 else if ( ROLE_CC
== eRole
)
729 mpCcList
= new AddressList_Impl();
732 else if ( ROLE_BCC
== eRole
)
736 mpBccList
= new AddressList_Impl();
741 SAL_WARN( "sfx2.dialog", "invalid address role" );
746 // add address to list
747 AddressItemPtr_Impl pAddress
= new String( rAddress
);
748 pList
->push_back( pAddress
);
753 SfxMailModel::SendMailResult
SfxMailModel::AttachDocument(
754 const OUString
& sDocumentType
,
755 const css::uno::Reference
< css::uno::XInterface
>& xFrameOrModel
,
756 const OUString
& sAttachmentTitle
)
760 SaveResult eSaveResult
= SaveDocumentAsFormat( sAttachmentTitle
, xFrameOrModel
, sDocumentType
, sFileName
);
761 if ( eSaveResult
== SAVE_SUCCESSFULL
&& !sFileName
.isEmpty() )
762 maAttachedDocuments
.push_back(sFileName
);
763 return eSaveResult
== SAVE_SUCCESSFULL
? SEND_MAIL_OK
: SEND_MAIL_ERROR
;
766 SfxMailModel::SendMailResult
SfxMailModel::Send( const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
768 OSL_ENSURE(!maAttachedDocuments
.empty(),"No document added!");
769 SendMailResult eResult
= SEND_MAIL_ERROR
;
770 if ( !maAttachedDocuments
.empty() )
772 css::uno::Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
774 css::uno::Reference
< XSimpleMailClientSupplier
> xSimpleMailClientSupplier
;
776 // Prefer the SimpleSystemMail service if available
778 xSimpleMailClientSupplier
= SimpleSystemMail::create( xContext
);
780 catch ( const uno::Exception
& )
783 if ( ! xSimpleMailClientSupplier
.is() )
786 xSimpleMailClientSupplier
= SimpleCommandMail::create( xContext
);
788 catch ( const uno::Exception
& )
792 if ( xSimpleMailClientSupplier
.is() )
794 css::uno::Reference
< XSimpleMailClient
> xSimpleMailClient
= xSimpleMailClientSupplier
->querySimpleMailClient();
796 if ( !xSimpleMailClient
.is() )
798 // no mail client support => message box!
799 return SEND_MAIL_ERROR
;
802 // we have a simple mail client
803 css::uno::Reference
< XSimpleMailMessage
> xSimpleMailMessage
= xSimpleMailClient
->createSimpleMailMessage();
804 if ( xSimpleMailMessage
.is() )
806 sal_Int32 nSendFlags
= SimpleMailClientFlags::DEFAULTS
;
807 if ( maFromAddress
.Len() == 0 )
809 // from address not set, try figure out users e-mail address
810 CreateFromAddress_Impl( maFromAddress
);
812 xSimpleMailMessage
->setOriginator( maFromAddress
);
814 size_t nToCount
= mpToList
? mpToList
->size() : 0;
815 size_t nCcCount
= mpCcList
? mpCcList
->size() : 0;
816 size_t nCcSeqCount
= nCcCount
;
818 // set recipient (only one) for this simple mail server!!
821 nCcSeqCount
= nToCount
- 1 + nCcCount
;
822 xSimpleMailMessage
->setRecipient( *mpToList
->at( 0 ) );
823 nSendFlags
= SimpleMailClientFlags::NO_USER_INTERFACE
;
825 else if ( nToCount
== 1 )
827 xSimpleMailMessage
->setRecipient( *mpToList
->at( 0 ) );
828 nSendFlags
= SimpleMailClientFlags::NO_USER_INTERFACE
;
831 // all other recipient must be handled with CC recipients!
832 if ( nCcSeqCount
> 0 )
835 Sequence
< OUString
> aCcRecipientSeq
;
837 aCcRecipientSeq
.realloc( nCcSeqCount
);
838 if ( nCcSeqCount
> nCcCount
)
840 for ( size_t i
= 1; i
< nToCount
; ++i
)
842 aCcRecipientSeq
[nIndex
++] = *mpToList
->at(i
);
846 for ( size_t i
= 0; i
< nCcCount
; i
++ )
848 aCcRecipientSeq
[nIndex
++] = *mpCcList
->at(i
);
850 xSimpleMailMessage
->setCcRecipient( aCcRecipientSeq
);
853 size_t nBccCount
= mpBccList
? mpBccList
->size() : 0;
856 Sequence
< OUString
> aBccRecipientSeq( nBccCount
);
857 for ( size_t i
= 0; i
< nBccCount
; ++i
)
859 aBccRecipientSeq
[i
] = *mpBccList
->at(i
);
861 xSimpleMailMessage
->setBccRecipient( aBccRecipientSeq
);
864 Sequence
< OUString
> aAttachmentSeq(&(maAttachedDocuments
[0]),maAttachedDocuments
.size());
866 if ( xSimpleMailMessage
->getSubject().isEmpty() ) {
867 OUString
baseName( maAttachedDocuments
[0].copy( maAttachedDocuments
[0].lastIndexOf( '/' ) + 1 ) );
868 OUString
subject( baseName
);
869 if ( maAttachedDocuments
.size() > 1 )
871 xSimpleMailMessage
->setSubject( subject
);
873 xSimpleMailMessage
->setAttachement( aAttachmentSeq
);
875 sal_Bool
bSend( sal_False
);
878 xSimpleMailClient
->sendSimpleMailMessage( xSimpleMailMessage
, nSendFlags
);
881 catch ( IllegalArgumentException
& )
888 if ( bSend
== sal_False
)
890 css::uno::Reference
< css::awt::XWindow
> xParentWindow
= xFrame
->getContainerWindow();
892 SolarMutexGuard aGuard
;
893 Window
* pParentWindow
= VCLUnoHelper::GetWindow( xParentWindow
);
895 ErrorBox
aBox( pParentWindow
, SfxResId( RID_ERRBOX_MAIL_CONFIG
));
897 eResult
= SEND_MAIL_CANCELLED
;
900 eResult
= SEND_MAIL_OK
;
905 eResult
= SEND_MAIL_CANCELLED
;
910 SfxMailModel::SendMailResult
SfxMailModel::SaveAndSend( const css::uno::Reference
< css::frame::XFrame
>& xFrame
, const OUString
& rTypeName
)
912 SaveResult eSaveResult
;
913 SendMailResult eResult
= SEND_MAIL_ERROR
;
916 eSaveResult
= SaveDocumentAsFormat( OUString(), xFrame
, rTypeName
, aFileName
);
918 if ( eSaveResult
== SAVE_SUCCESSFULL
)
920 maAttachedDocuments
.push_back( aFileName
);
921 return Send( xFrame
);
923 else if ( eSaveResult
== SAVE_CANCELLED
)
924 eResult
= SEND_MAIL_CANCELLED
;
929 // functions -------------------------------------------------------------
931 sal_Bool
CreateFromAddress_Impl( String
& rFrom
)
935 This function tries to create a From-address with the help of IniManagers.
936 For this the fields 'first name', 'Name' and 'Email' are read from the
937 application-ini-data. If these fields are not set, FALSE is returned.
941 sal_True: Address could be created.
942 sal_False: Address could not be created.
946 SvtUserOptions aUserCFG
;
947 String aName
= aUserCFG
.GetLastName ();
948 String aFirstName
= aUserCFG
.GetFirstName ();
949 if ( aFirstName
.Len() || aName
.Len() )
951 if ( aFirstName
.Len() )
953 rFrom
= comphelper::string::strip(aFirstName
, ' ');
958 rFrom
+= comphelper::string::strip(aName
, ' ');
959 // remove illegal characters
960 rFrom
= comphelper::string::remove(rFrom
, '<');
961 rFrom
= comphelper::string::remove(rFrom
, '>');
962 rFrom
= comphelper::string::remove(rFrom
, '@');
964 String aEmailName
= aUserCFG
.GetEmail();
966 // remove illegal characters
967 aEmailName
= comphelper::string::remove(aEmailName
, '<');
968 aEmailName
= comphelper::string::remove(aEmailName
, '>');
970 if ( aEmailName
.Len() )
974 ( ( rFrom
+= '<' ) += comphelper::string::strip(aEmailName
, ' ') ) += '>';
978 return ( rFrom
.Len() > 0 );
981 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */