1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "mmoutputtypepage.hxx"
21 #include <mailmergewizard.hxx>
22 #include <mmconfigitem.hxx>
24 #include <strings.hrc>
25 #include <bitmaps.hlst>
26 #include <swtypes.hxx>
28 #include <rtl/ref.hxx>
29 #include <com/sun/star/mail/XSmtpService.hpp>
30 #include <vcl/idle.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/weld.hxx>
35 #include <swunohelper.hxx>
36 #include <mmresultdialogs.hxx>
37 #include <maildispatcher.hxx>
38 #include <imaildsplistener.hxx>
40 using namespace ::com::sun::star
;
42 SwMailMergeOutputTypePage::SwMailMergeOutputTypePage(weld::Container
* pPage
, SwMailMergeWizard
* pWizard
)
43 : vcl::OWizardPage(pPage
, pWizard
, "modules/swriter/ui/mmoutputtypepage.ui", "MMOutputTypePage")
45 , m_xLetterRB(m_xBuilder
->weld_radio_button("letter"))
46 , m_xMailRB(m_xBuilder
->weld_radio_button("email"))
47 , m_xLetterHint(m_xBuilder
->weld_label("letterft"))
48 , m_xMailHint(m_xBuilder
->weld_label("emailft"))
50 Link
<weld::ToggleButton
&,void> aLink
= LINK(this, SwMailMergeOutputTypePage
, TypeHdl_Impl
);
51 m_xLetterRB
->connect_toggled(aLink
);
52 m_xMailRB
->connect_toggled(aLink
);
54 SwMailMergeConfigItem
& rConfigItem
= m_pWizard
->GetConfigItem();
55 if(rConfigItem
.IsOutputToLetter())
56 m_xLetterRB
->set_active(true);
58 m_xMailRB
->set_active(true);
59 TypeHdl_Impl(*m_xLetterRB
);
62 SwMailMergeOutputTypePage::~SwMailMergeOutputTypePage()
66 IMPL_LINK_NOARG(SwMailMergeOutputTypePage
, TypeHdl_Impl
, weld::ToggleButton
&, void)
68 bool bLetter
= m_xLetterRB
->get_active();
69 m_xLetterHint
->set_visible(bLetter
);
70 m_xMailHint
->set_visible(!bLetter
);
71 m_pWizard
->GetConfigItem().SetOutputToLetter(bLetter
);
72 m_pWizard
->UpdateRoadmap();
75 struct SwSendMailDialog_Impl
77 friend class SwSendMailDialog
;
78 ::osl::Mutex aDescriptorMutex
;
80 std::vector
< SwMailDescriptor
> aDescriptors
;
81 sal_uInt32 nCurrentDescriptor
;
82 ::rtl::Reference
< MailDispatcher
> xMailDispatcher
;
83 ::rtl::Reference
< IMailDispatcherListener
> xMailListener
;
84 uno::Reference
< mail::XMailService
> xConnectedInMailService
;
87 SwSendMailDialog_Impl() :
90 aRemoveIdle
.SetPriority(TaskPriority::LOWEST
);
93 ~SwSendMailDialog_Impl()
95 // Shutdown must be called when the last reference to the
96 // mail dispatcher will be released in order to force a
97 // shutdown of the mail dispatcher thread.
98 // 'join' with the mail dispatcher thread leads to a
99 // deadlock (SolarMutex).
100 if( xMailDispatcher
.is() && !xMailDispatcher
->isShutdownRequested() )
101 xMailDispatcher
->shutdown();
103 const SwMailDescriptor
* GetNextDescriptor();
106 const SwMailDescriptor
* SwSendMailDialog_Impl::GetNextDescriptor()
108 ::osl::MutexGuard
aGuard(aDescriptorMutex
);
109 if(nCurrentDescriptor
< aDescriptors
.size())
111 ++nCurrentDescriptor
;
112 return &aDescriptors
[nCurrentDescriptor
- 1];
117 class SwMailDispatcherListener_Impl
: public IMailDispatcherListener
119 SwSendMailDialog
& m_rSendMailDialog
;
122 explicit SwMailDispatcherListener_Impl(SwSendMailDialog
& rParentDlg
);
124 virtual void idle(::rtl::Reference
<MailDispatcher
> xMailDispatcher
) override
;
125 virtual void mailDelivered(::rtl::Reference
<MailDispatcher
> xMailDispatcher
,
126 uno::Reference
< mail::XMailMessage
> xMailMessage
) override
;
127 virtual void mailDeliveryError(::rtl::Reference
<MailDispatcher
> xMailDispatcher
,
128 uno::Reference
< mail::XMailMessage
> xMailMessage
, const OUString
& sErrorMessage
) override
;
130 static void DeleteAttachments( uno::Reference
< mail::XMailMessage
> const & xMessage
);
133 SwMailDispatcherListener_Impl::SwMailDispatcherListener_Impl(SwSendMailDialog
& rParentDlg
)
134 : m_rSendMailDialog(rParentDlg
)
138 void SwMailDispatcherListener_Impl::idle(::rtl::Reference
<MailDispatcher
> /*xMailDispatcher*/)
140 SolarMutexGuard aGuard
;
141 m_rSendMailDialog
.AllMailsSent();
144 void SwMailDispatcherListener_Impl::mailDelivered(
145 ::rtl::Reference
<MailDispatcher
> /*xMailDispatcher*/,
146 uno::Reference
< mail::XMailMessage
> xMailMessage
)
148 SolarMutexGuard aGuard
;
149 m_rSendMailDialog
.DocumentSent( xMailMessage
, true, nullptr );
150 DeleteAttachments( xMailMessage
);
153 void SwMailDispatcherListener_Impl::mailDeliveryError(
154 ::rtl::Reference
<MailDispatcher
> /*xMailDispatcher*/,
155 uno::Reference
< mail::XMailMessage
> xMailMessage
,
156 const OUString
& sErrorMessage
)
158 SolarMutexGuard aGuard
;
159 m_rSendMailDialog
.DocumentSent( xMailMessage
, false, &sErrorMessage
);
160 DeleteAttachments( xMailMessage
);
163 void SwMailDispatcherListener_Impl::DeleteAttachments( uno::Reference
< mail::XMailMessage
> const & xMessage
)
165 const uno::Sequence
< mail::MailAttachment
> aAttachments
= xMessage
->getAttachments();
167 for(const auto& rAttachment
: aAttachments
)
171 uno::Reference
< beans::XPropertySet
> xTransferableProperties( rAttachment
.Data
, uno::UNO_QUERY_THROW
);
173 xTransferableProperties
->getPropertyValue("URL") >>= sURL
;
175 SWUnoHelper::UCB_DeleteFile( sURL
);
177 catch (const uno::Exception
&)
183 class SwSendWarningBox_Impl
: public weld::MessageDialogController
185 std::unique_ptr
<weld::TextView
> m_xDetailED
;
187 SwSendWarningBox_Impl(weld::Window
* pParent
, const OUString
& rDetails
)
188 : MessageDialogController(pParent
, "modules/swriter/ui/warnemaildialog.ui", "WarnEmailDialog", "grid")
189 , m_xDetailED(m_xBuilder
->weld_text_view("errors"))
191 m_xDetailED
->set_size_request(80 * m_xDetailED
->get_approximate_digit_width(),
192 8 * m_xDetailED
->get_text_height());
193 m_xDetailED
->set_text(rDetails
);
197 SwSendMailDialog::SwSendMailDialog(weld::Window
*pParent
, SwMailMergeConfigItem
& rConfigItem
)
198 : GenericDialogController(pParent
, "modules/swriter/ui/mmsendmails.ui", "SendMailsDialog")
199 , m_sContinue(SwResId( ST_CONTINUE
))
200 , m_sSendingTo( SwResId(ST_SENDINGTO
))
201 , m_sCompleted( SwResId(ST_COMPLETED
))
202 , m_sFailed( SwResId(ST_FAILED
))
204 , m_bDestructionEnabled(false)
205 , m_pImpl(new SwSendMailDialog_Impl
)
206 , m_pConfigItem(&rConfigItem
)
207 , m_nExpectedCount(0)
210 , m_xTransferStatus(m_xBuilder
->weld_label("transferstatus"))
211 , m_xPaused(m_xBuilder
->weld_label("paused"))
212 , m_xProgressBar(m_xBuilder
->weld_progress_bar("progress"))
213 , m_xErrorStatus(m_xBuilder
->weld_label("errorstatus"))
214 , m_xStatus(m_xBuilder
->weld_tree_view("container"))
215 , m_xStop(m_xBuilder
->weld_button("stop"))
216 , m_xClose(m_xBuilder
->weld_button("cancel"))
217 , m_xExpander(m_xBuilder
->weld_expander("details"))
219 m_sStop
= m_xStop
->get_label();
220 m_sTransferStatus
= m_xTransferStatus
->get_label();
221 m_sErrorStatus
= m_xErrorStatus
->get_label();
223 Size
aSize(m_xStatus
->get_approximate_digit_width() * 28,
224 m_xStatus
->get_height_rows(20));
225 m_xStatus
->set_size_request(aSize
.Width(), aSize
.Height());
227 m_xStop
->connect_clicked(LINK( this, SwSendMailDialog
, StopHdl_Impl
));
228 m_xClose
->connect_clicked(LINK( this, SwSendMailDialog
, CloseHdl_Impl
));
230 std::vector
<int> aWidths
;
231 aWidths
.push_back(m_xStatus
->get_checkbox_column_width());
232 aWidths
.push_back(aSize
.Width()/3 * 2);
233 m_xStatus
->set_column_fixed_widths(aWidths
);
235 m_xPaused
->set_visible(false);
236 UpdateTransferStatus();
239 SwSendMailDialog::~SwSendMailDialog()
241 if(m_pImpl
->xMailDispatcher
.is())
245 if(m_pImpl
->xMailDispatcher
->isStarted())
246 m_pImpl
->xMailDispatcher
->stop();
247 if(m_pImpl
->xConnectedInMailService
.is() && m_pImpl
->xConnectedInMailService
->isConnected())
248 m_pImpl
->xConnectedInMailService
->disconnect();
250 uno::Reference
<mail::XMailMessage
> xMessage
=
251 m_pImpl
->xMailDispatcher
->dequeueMailMessage();
254 SwMailDispatcherListener_Impl::DeleteAttachments( xMessage
);
255 xMessage
= m_pImpl
->xMailDispatcher
->dequeueMailMessage();
258 catch (const uno::Exception
&)
264 void SwSendMailDialog::AddDocument( SwMailDescriptor
const & rDesc
)
266 ::osl::MutexGuard
aGuard(m_pImpl
->aDescriptorMutex
);
267 m_pImpl
->aDescriptors
.push_back(rDesc
);
268 // if the dialog is already running then continue sending of documents
269 if(m_pImpl
->xMailDispatcher
.is())
275 IMPL_LINK( SwSendMailDialog
, StopHdl_Impl
, weld::Button
&, rButton
, void )
278 if(m_pImpl
->xMailDispatcher
.is())
280 if(m_pImpl
->xMailDispatcher
->isStarted())
282 m_pImpl
->xMailDispatcher
->stop();
283 rButton
.set_label(m_sContinue
);
288 m_pImpl
->xMailDispatcher
->start();
289 rButton
.set_label(m_sStop
);
295 IMPL_LINK_NOARG(SwSendMailDialog
, CloseHdl_Impl
, weld::Button
&, void)
299 if (m_bDestructionEnabled
)
300 m_xDialog
->response(RET_CANCEL
);
303 m_pImpl
->aRemoveIdle
.SetInvokeHandler( LINK( this, SwSendMailDialog
, RemoveThis
) );
304 m_pImpl
->aRemoveIdle
.Start();
308 IMPL_STATIC_LINK( SwSendMailDialog
, StartSendMails
, void*, pDialog
, void )
310 static_cast<SwSendMailDialog
*>(pDialog
)->SendMails();
313 IMPL_LINK( SwSendMailDialog
, RemoveThis
, Timer
*, pTimer
, void )
315 if( m_pImpl
->xMailDispatcher
.is() )
317 if(m_pImpl
->xMailDispatcher
->isStarted())
318 m_pImpl
->xMailDispatcher
->stop();
319 if(!m_pImpl
->xMailDispatcher
->isShutdownRequested())
320 m_pImpl
->xMailDispatcher
->shutdown();
323 if( m_bDestructionEnabled
&&
324 (!m_pImpl
->xMailDispatcher
.is() ||
325 !m_pImpl
->xMailDispatcher
->isRunning()))
327 m_xDialog
->response(RET_CANCEL
);
335 IMPL_STATIC_LINK( SwSendMailDialog
, StopSendMails
, void*, p
, void )
337 SwSendMailDialog
* pDialog
= static_cast<SwSendMailDialog
*>(p
);
338 if(pDialog
->m_pImpl
->xMailDispatcher
.is() &&
339 pDialog
->m_pImpl
->xMailDispatcher
->isStarted())
341 pDialog
->m_pImpl
->xMailDispatcher
->stop();
342 pDialog
->m_xStop
->set_label(pDialog
->m_sContinue
);
343 pDialog
->m_xPaused
->show();
347 void SwSendMailDialog::SendMails()
351 OSL_FAIL("config item not set");
354 auto xWait(std::make_unique
<weld::WaitObject
>(m_xDialog
.get()));
355 //get a mail server connection
356 uno::Reference
< mail::XSmtpService
> xSmtpServer
=
357 SwMailMergeHelper::ConnectToSmtpServer( *m_pConfigItem
,
358 m_pImpl
->xConnectedInMailService
,
359 OUString(), OUString(), m_xDialog
.get());
360 bool bIsLoggedIn
= xSmtpServer
.is() && xSmtpServer
->isConnected();
364 OSL_FAIL("create error message");
367 m_pImpl
->xMailDispatcher
.set( new MailDispatcher(xSmtpServer
));
369 m_pImpl
->xMailListener
= new SwMailDispatcherListener_Impl(*this);
370 m_pImpl
->xMailDispatcher
->addListener(m_pImpl
->xMailListener
);
373 m_pImpl
->xMailDispatcher
->start();
377 void SwSendMailDialog::IterateMails()
379 const SwMailDescriptor
* pCurrentMailDescriptor
= m_pImpl
->GetNextDescriptor();
380 while( pCurrentMailDescriptor
)
382 if (!SwMailMergeHelper::CheckMailAddress( pCurrentMailDescriptor
->sEMail
))
384 OUString sMessage
= m_sSendingTo
;
386 m_xStatus
->set_image(m_nSendCount
, RID_BMP_FORMULA_CANCEL
, 0);
387 m_xStatus
->set_text(m_nSendCount
, sMessage
.replaceFirst("%1", pCurrentMailDescriptor
->sEMail
), 1);
388 m_xStatus
->set_text(m_nSendCount
, m_sFailed
, 1);
391 UpdateTransferStatus( );
392 pCurrentMailDescriptor
= m_pImpl
->GetNextDescriptor();
395 SwMailMessage
* pMessage
= new SwMailMessage
;
396 uno::Reference
< mail::XMailMessage
> xMessage
= pMessage
;
397 if(m_pConfigItem
->IsMailReplyTo())
398 pMessage
->setReplyToAddress(m_pConfigItem
->GetMailReplyTo());
399 pMessage
->addRecipient( pCurrentMailDescriptor
->sEMail
);
400 pMessage
->SetSenderName( m_pConfigItem
->GetMailDisplayName() );
401 pMessage
->SetSenderAddress( m_pConfigItem
->GetMailAddress() );
402 if(!pCurrentMailDescriptor
->sAttachmentURL
.isEmpty())
404 mail::MailAttachment aAttach
;
406 new SwMailTransferable(
407 pCurrentMailDescriptor
->sAttachmentURL
,
408 pCurrentMailDescriptor
->sAttachmentName
,
409 pCurrentMailDescriptor
->sMimeType
);
410 aAttach
.ReadableName
= pCurrentMailDescriptor
->sAttachmentName
;
411 pMessage
->addAttachment( aAttach
);
413 pMessage
->setSubject( pCurrentMailDescriptor
->sSubject
);
414 uno::Reference
< datatransfer::XTransferable
> xBody
=
415 new SwMailTransferable(
416 pCurrentMailDescriptor
->sBodyContent
,
417 pCurrentMailDescriptor
->sBodyMimeType
);
418 pMessage
->setBody( xBody
);
420 //CC and BCC are tokenized by ';'
421 if(!pCurrentMailDescriptor
->sCC
.isEmpty())
426 OUString sTmp
= pCurrentMailDescriptor
->sCC
.getToken( 0, ';', nPos
);
427 if( !sTmp
.isEmpty() )
428 pMessage
->addCcRecipient( sTmp
);
432 if(!pCurrentMailDescriptor
->sBCC
.isEmpty())
437 OUString sTmp
= pCurrentMailDescriptor
->sBCC
.getToken( 0, ';', nPos
);
438 if( !sTmp
.isEmpty() )
439 pMessage
->addBccRecipient( sTmp
);
443 m_pImpl
->xMailDispatcher
->enqueueMailMessage( xMessage
);
444 pCurrentMailDescriptor
= m_pImpl
->GetNextDescriptor();
446 UpdateTransferStatus();
449 void SwSendMailDialog::StartSend(sal_Int32 nExpectedCount
)
451 Application::PostUserEvent( LINK( this, SwSendMailDialog
,
452 StartSendMails
), this );
453 m_nExpectedCount
= nExpectedCount
> 0 ? nExpectedCount
: 1;
456 void SwSendMailDialog::DocumentSent( uno::Reference
< mail::XMailMessage
> const & xMessage
,
458 const OUString
* pError
)
460 //sending should stop on send errors
462 m_pImpl
->xMailDispatcher
.is() && m_pImpl
->xMailDispatcher
->isStarted())
464 Application::PostUserEvent( LINK( this, SwSendMailDialog
,
465 StopSendMails
), this );
467 OUString
sInsertImg(bResult
? OUString(RID_BMP_FORMULA_APPLY
) : OUString(RID_BMP_FORMULA_CANCEL
));
469 OUString sMessage
= m_sSendingTo
;
471 m_xStatus
->set_image(m_nSendCount
, sInsertImg
, 0);
472 m_xStatus
->set_text(m_nSendCount
, sMessage
.replaceFirst("%1", xMessage
->getRecipients()[0]), 1);
473 m_xStatus
->set_text(m_nSendCount
, bResult
? m_sCompleted
: m_sFailed
, 1);
478 UpdateTransferStatus( );
482 SwSendWarningBox_Impl
aDlg(m_xDialog
.get(), *pError
);
487 void SwSendMailDialog::UpdateTransferStatus()
489 OUString
sStatus( m_sTransferStatus
);
490 sStatus
= sStatus
.replaceFirst("%1", OUString::number(m_nSendCount
) );
491 sStatus
= sStatus
.replaceFirst("%2", OUString::number(m_nExpectedCount
));
492 m_xTransferStatus
->set_label(sStatus
);
494 sStatus
= m_sErrorStatus
.replaceFirst("%1", OUString::number(m_nErrorCount
) );
495 m_xErrorStatus
->set_label(sStatus
);
497 if (!m_pImpl
->aDescriptors
.empty())
499 assert(m_nExpectedCount
&& "div-by-zero");
500 m_xProgressBar
->set_percentage(m_nSendCount
* 100 / m_nExpectedCount
);
503 m_xProgressBar
->set_percentage(0);
506 void SwSendMailDialog::AllMailsSent()
508 // Leave open if some kind of error occurred
509 if (m_nSendCount
== m_nExpectedCount
)
511 m_xStop
->set_sensitive(false);
513 m_xDialog
->response(RET_CANCEL
);
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */