bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / dialog / mailmodel.cxx
blob521b74f1f72dd9d763027ebf635068caec6e202d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
51 #include <rtl/uri.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>
60 #include "dialog.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 >
90 bool m_bState;
91 public:
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() :
107 m_bState( false )
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;
119 else
120 m_bState = false;
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,
136 bool bModified,
137 sal_Int32& rNumArgs,
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() )
152 return eRet;
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 );
194 if( xExporter.is() )
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;
212 break;
215 eRet = SAVE_SUCCESSFULL;
217 else
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.
223 if ( !bModified )
227 xModifiable->setModified( sal_False );
229 catch( com::sun::star::beans::PropertyVetoException& )
233 eRet = SAVE_CANCELLED;
236 break;
242 catch( css::uno::RuntimeException& )
244 throw;
246 catch( uno::Exception& )
250 return eRet;
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();
269 if (!xContext.is())
270 return eRet;
272 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
274 OUString aModule;
277 aModule = xModuleManager->identify( xFrameOrModel );
279 catch ( css::uno::RuntimeException& )
281 throw;
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 );
289 if ( xFrame.is() )
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() )
319 bStoreTo = true;
321 if ( xStorable.is() )
323 OUString aFilterName;
324 OUString aTypeName( rType );
325 OUString aFileName;
326 OUString aExtension;
328 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
329 xSMGR->createInstance( OUString(
330 "com.sun.star.document.FilterFactory" )),
331 css::uno::UNO_QUERY );
333 if ( bStoreTo )
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 );
341 if( bSendAsPDF )
343 // #i91419#
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(
359 OUString("Name"),
360 OUString() );
363 if ( bHasLocation )
365 // Retrieve filter from media descriptor
366 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
367 OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
368 OUString( "FilterName" ),
369 OUString() );
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
374 // bStoreTo flag.
375 bStoreTo = false;
379 else
381 if ( bHasLocation )
383 // Retrieve filter from media descriptor
384 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
385 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
386 OUString( "FilterName" ),
387 OUString() );
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"),
398 OUString() );
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(
405 OUString("Type"),
406 OUString() );
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 ))
422 return eRet;
424 // Determine file name and extension
425 if ( bHasLocation && !bStoreTo )
427 INetURLObject aFileObj( xStorable->getLocation() );
428 aExtension = aFileObj.getExtension();
430 else
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() )
459 if ( !bHasLocation )
461 // Create a noname file name with the correct extension
462 const OUString aNoNameFileName( "noname" );
463 aFileName = aNoNameFileName;
465 else
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() )
475 return eRet;
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(
500 aPasswordPropName,
501 OUString() );
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 ) );
514 if( !bSendAsPDF )
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& )
539 throw;
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& )
562 throw;
564 catch ( css::uno::Exception& )
570 //check if this is the pdf otput filter (i#64555)
571 if( bSendAsPDF )
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;
585 if( !bSendAsPDF )
587 css::util::URL aURL;
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& )
605 throw;
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.
616 if ( !bModified )
620 xModifiable->setModified( sal_False );
622 catch( com::sun::star::beans::PropertyVetoException& )
627 catch ( com::sun::star::io::IOException& )
629 eRet = SAVE_ERROR;
632 else
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& )
647 eRet = SAVE_ERROR;
653 return eRet;
656 SfxMailModel::SfxMailModel() :
657 mpToList ( NULL ),
658 mpCcList ( NULL ),
659 mpBccList ( NULL ),
660 mePriority ( PRIO_NORMAL ),
661 mbLoadDone ( true )
665 SfxMailModel::~SfxMailModel()
667 delete mpToList;
668 delete mpCcList;
669 delete mpBccList;
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 )
680 if ( !mpToList )
681 // create the list
682 mpToList = new AddressList_Impl();
683 pList = mpToList;
685 else if ( ROLE_CC == eRole )
687 if ( !mpCcList )
688 // create the list
689 mpCcList = new AddressList_Impl();
690 pList = mpCcList;
692 else if ( ROLE_BCC == eRole )
694 if ( !mpBccList )
695 // create the list
696 mpBccList = new AddressList_Impl();
697 pList = mpBccList;
699 else
701 SAL_WARN( "sfx.dialog", "invalid address role" );
704 if ( pList )
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 )
717 OUString sFileName;
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
736 try {
737 xSimpleMailClientSupplier = SimpleSystemMail::create( xContext );
739 catch ( const uno::Exception & )
742 if ( ! xSimpleMailClientSupplier.is() )
744 try {
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!!
778 if ( nToCount > 1 )
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 )
793 size_t nIndex = 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;
813 if ( nBccCount > 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() ) {
826 INetURLObject url(
827 maAttachedDocuments[0], INetURLObject::WAS_ENCODED);
828 OUString subject(
829 url.getBase(
830 INetURLObject::LAST_SEGMENT, false,
831 #ifdef WNT
832 INetURLObject::NO_DECODE)); // MAPISendMail does not accept Unicode
833 #else
834 INetURLObject::DECODE_WITH_CHARSET));
835 #endif
836 if (subject.isEmpty()) {
837 subject = maAttachedDocuments[0];
839 if ( maAttachedDocuments.size() > 1 )
840 subject += ", ...";
841 xSimpleMailMessage->setSubject( subject );
843 xSimpleMailMessage->setAttachement( aAttachmentSeq );
845 bool bSend( false );
848 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
849 bSend = true;
851 catch ( IllegalArgumentException& )
854 catch ( Exception& )
858 if ( !bSend )
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");
866 aBox->Execute();
867 eResult = SEND_MAIL_CANCELLED;
869 else
870 eResult = SEND_MAIL_OK;
874 else
875 eResult = SEND_MAIL_CANCELLED;
877 return eResult;
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;
884 OUString aFileName;
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;
896 return eResult;
899 // functions -------------------------------------------------------------
901 bool CreateFromAddress_Impl( OUString& rFrom )
903 /* [Description]
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.
909 [Return value]
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() )
926 rFrom += " ";
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() )
943 rFrom += " ";
944 rFrom = rFrom + "<" + comphelper::string::strip(aEmailName, ' ') + ">";
946 else
947 rFrom.clear();
948 return !rFrom.isEmpty();
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */