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