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