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