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