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