LibreOffice Module sw (master) 1
mmoutputtypepage.cxx
Go to the documentation of this file.
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 "mmoutputtypepage.hxx"
21#include <mailmergewizard.hxx>
22#include <mmconfigitem.hxx>
23#include <strings.hrc>
24#include <bitmaps.hlst>
25#include <swtypes.hxx>
26
27#include <rtl/ref.hxx>
28#include <com/sun/star/mail/XSmtpService.hpp>
29#include <vcl/idle.hxx>
30#include <vcl/svapp.hxx>
31#include <vcl/weld.hxx>
32
33#include <swunohelper.hxx>
34#include <mmresultdialogs.hxx>
35#include <maildispatcher.hxx>
36#include <imaildsplistener.hxx>
37#include <mutex>
38
39using namespace ::com::sun::star;
40
42 : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmoutputtypepage.ui", "MMOutputTypePage")
43 , m_pWizard(pWizard)
44 , m_xLetterRB(m_xBuilder->weld_radio_button("letter"))
45 , m_xMailRB(m_xBuilder->weld_radio_button("email"))
46 , m_xLetterHint(m_xBuilder->weld_label("letterft"))
47 , m_xMailHint(m_xBuilder->weld_label("emailft"))
48{
50 m_xLetterRB->connect_toggled(aLink);
51 m_xMailRB->connect_toggled(aLink);
52
54 if(rConfigItem.IsOutputToLetter())
55 m_xLetterRB->set_active(true);
56 else
57 m_xMailRB->set_active(true);
58 TypeHdl_Impl(*m_xLetterRB);
59}
60
62{
63}
64
66{
67 bool bLetter = m_xLetterRB->get_active();
68 m_xLetterHint->set_visible(bLetter);
69 m_xMailHint->set_visible(!bLetter);
70 m_pWizard->GetConfigItem().SetOutputToLetter(bLetter);
71 m_pWizard->UpdateRoadmap();
72}
73
75{
76 friend class SwSendMailDialog;
77 // The mutex is locked in SwSendMailDialog_Impl::GetNextDescriptor, which may be called
78 // both with mutex unlocked (inside SwSendMailDialog::SendMails), and with mutex locked
79 // (inside SwSendMailDialog::AddDocument).
80 std::recursive_mutex aDescriptorMutex;
81
82 std::vector< SwMailDescriptor > aDescriptors;
86 uno::Reference< mail::XMailService > xConnectedInMailService;
88
90 nCurrentDescriptor(0), aRemoveIdle("SwSendMailDialog_Impl aRemoveIdle")
91 {
92 aRemoveIdle.SetPriority(TaskPriority::LOWEST);
93 }
94
96 {
97 // Shutdown must be called when the last reference to the
98 // mail dispatcher will be released in order to force a
99 // shutdown of the mail dispatcher thread.
100 // 'join' with the mail dispatcher thread leads to a
101 // deadlock (SolarMutex).
102 if( xMailDispatcher.is() && !xMailDispatcher->isShutdownRequested() )
103 xMailDispatcher->shutdown();
104 }
106};
107
109{
110 std::scoped_lock aGuard(aDescriptorMutex);
112 {
114 return &aDescriptors[nCurrentDescriptor - 1];
115 }
116 return nullptr;
117}
118
119namespace {
120
121class SwMailDispatcherListener_Impl : public IMailDispatcherListener
122{
123 SwSendMailDialog& m_rSendMailDialog;
124
125public:
126 explicit SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg);
127
128 virtual void idle() override;
129 virtual void mailDelivered(uno::Reference< mail::XMailMessage> xMailMessage) override;
130 virtual void mailDeliveryError(::rtl::Reference<MailDispatcher> xMailDispatcher,
131 uno::Reference< mail::XMailMessage> xMailMessage, const OUString& sErrorMessage) override;
132
133 static void DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage );
134};
135
136}
137
138SwMailDispatcherListener_Impl::SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg)
139 : m_rSendMailDialog(rParentDlg)
140{
141}
142
143void SwMailDispatcherListener_Impl::idle()
144{
145 SolarMutexGuard aGuard;
146 m_rSendMailDialog.AllMailsSent();
147}
148
149void SwMailDispatcherListener_Impl::mailDelivered(
150 uno::Reference< mail::XMailMessage> xMailMessage)
151{
152 SolarMutexGuard aGuard;
153 m_rSendMailDialog.DocumentSent( xMailMessage, true, nullptr );
154 DeleteAttachments( xMailMessage );
155}
156
157void SwMailDispatcherListener_Impl::mailDeliveryError(
158 ::rtl::Reference<MailDispatcher> /*xMailDispatcher*/,
159 uno::Reference< mail::XMailMessage> xMailMessage,
160 const OUString& sErrorMessage)
161{
162 SolarMutexGuard aGuard;
163 m_rSendMailDialog.DocumentSent( xMailMessage, false, &sErrorMessage );
164 DeleteAttachments( xMailMessage );
165}
166
167void SwMailDispatcherListener_Impl::DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage )
168{
169 const uno::Sequence< mail::MailAttachment > aAttachments = xMessage->getAttachments();
170
171 for(const auto& rAttachment : aAttachments)
172 {
173 try
174 {
175 uno::Reference< beans::XPropertySet > xTransferableProperties( rAttachment.Data, uno::UNO_QUERY_THROW);
176 OUString sURL;
177 xTransferableProperties->getPropertyValue("URL") >>= sURL;
178 if(!sURL.isEmpty())
180 }
181 catch (const uno::Exception&)
182 {
183 }
184 }
185}
186
187namespace {
188
189class SwSendWarningBox_Impl : public weld::MessageDialogController
190{
191 std::unique_ptr<weld::TextView> m_xDetailED;
192public:
193 SwSendWarningBox_Impl(weld::Window* pParent, const OUString& rDetails)
194 : MessageDialogController(pParent, "modules/swriter/ui/warnemaildialog.ui", "WarnEmailDialog", "grid")
195 , m_xDetailED(m_xBuilder->weld_text_view("errors"))
196 {
197 m_xDetailED->set_size_request(80 * m_xDetailED->get_approximate_digit_width(),
198 8 * m_xDetailED->get_text_height());
199 m_xDetailED->set_text(rDetails);
200 }
201};
202
203}
204
206 : GenericDialogController(pParent, "modules/swriter/ui/mmsendmails.ui", "SendMailsDialog")
207 , m_sContinue(SwResId( ST_CONTINUE ))
208 , m_sClose(SwResId(ST_CLOSE_DIALOG))
209 , m_sSendingTo( SwResId(ST_SENDINGTO ))
210 , m_sCompleted( SwResId(ST_COMPLETED ))
211 , m_sFailed( SwResId(ST_FAILED ))
212 , m_sAddressInvalid(SwResId(ST_ADDRESS_INVALID))
213 , m_bCancel(false)
214 , m_bDestructionEnabled(false)
216 , m_pConfigItem(&rConfigItem)
217 , m_nExpectedCount(0)
218 , m_nProcessedCount(0)
219 , m_nErrorCount(0)
220 , m_xTransferStatus(m_xBuilder->weld_label("transferstatus"))
221 , m_xPaused(m_xBuilder->weld_label("paused"))
222 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
223 , m_xErrorStatus(m_xBuilder->weld_label("errorstatus"))
224 , m_xStatus(m_xBuilder->weld_tree_view("container"))
225 , m_xStop(m_xBuilder->weld_button("stop"))
226 , m_xCancel(m_xBuilder->weld_button("cancel"))
227{
228 m_sStop = m_xStop->get_label();
230 m_sErrorStatus = m_xErrorStatus->get_label();
231
232 Size aSize(m_xStatus->get_approximate_digit_width() * 28,
233 m_xStatus->get_height_rows(20));
234 m_xStatus->set_size_request(aSize.Width(), aSize.Height());
235
236 m_xStop->connect_clicked(LINK( this, SwSendMailDialog, StopHdl_Impl));
237 m_xCancel->connect_clicked(LINK( this, SwSendMailDialog, CancelHdl_Impl));
238
239 std::vector<int> aWidths
240 {
241 o3tl::narrowing<int>(m_xStatus->get_checkbox_column_width()),
242 o3tl::narrowing<int>(aSize.Width()/3 * 2)
243 };
244 m_xStatus->set_column_fixed_widths(aWidths);
245
246 m_xPaused->set_visible(false);
248}
249
251{
252 if(!m_pImpl->xMailDispatcher.is())
253 return;
254
255 try
256 {
257 if(m_pImpl->xMailDispatcher->isStarted())
258 m_pImpl->xMailDispatcher->stop();
259 if(m_pImpl->xConnectedInMailService.is() && m_pImpl->xConnectedInMailService->isConnected())
260 m_pImpl->xConnectedInMailService->disconnect();
261
262 uno::Reference<mail::XMailMessage> xMessage =
263 m_pImpl->xMailDispatcher->dequeueMailMessage();
264 while(xMessage.is())
265 {
266 SwMailDispatcherListener_Impl::DeleteAttachments( xMessage );
267 xMessage = m_pImpl->xMailDispatcher->dequeueMailMessage();
268 }
269 }
270 catch (const uno::Exception&)
271 {
272 }
273}
274
276{
277 std::scoped_lock aGuard(m_pImpl->aDescriptorMutex);
278 m_pImpl->aDescriptors.push_back(rDesc);
279 // if the dialog is already running then continue sending of documents
280 if(m_pImpl->xMailDispatcher.is())
281 {
282 IterateMails();
283 }
284}
285
286IMPL_LINK( SwSendMailDialog, StopHdl_Impl, weld::Button&, rButton, void )
287{
288 m_bCancel = true;
289 if(!m_pImpl->xMailDispatcher.is())
290 return;
291
292 if(m_pImpl->xMailDispatcher->isStarted())
293 {
294 m_pImpl->xMailDispatcher->stop();
295 rButton.set_label(m_sContinue);
296 m_xPaused->show();
297 }
298 else
299 {
300 m_pImpl->xMailDispatcher->start();
301 rButton.set_label(m_sStop);
302 m_xPaused->hide();
303 }
304}
305
307{
308 m_xDialog->hide();
309
310 if (m_bDestructionEnabled)
311 m_xDialog->response(RET_CANCEL);
312 else
313 {
314 m_pImpl->aRemoveIdle.SetInvokeHandler( LINK( this, SwSendMailDialog, RemoveThis ) );
315 m_pImpl->aRemoveIdle.Start();
316 }
317}
318
319IMPL_STATIC_LINK( SwSendMailDialog, StartSendMails, void*, pDialog, void )
320{
321 static_cast<SwSendMailDialog*>(pDialog)->SendMails();
322}
323
324IMPL_LINK( SwSendMailDialog, RemoveThis, Timer*, pTimer, void )
325{
326 if( m_pImpl->xMailDispatcher.is() )
327 {
328 if(m_pImpl->xMailDispatcher->isStarted())
329 m_pImpl->xMailDispatcher->stop();
330 if(!m_pImpl->xMailDispatcher->isShutdownRequested())
331 m_pImpl->xMailDispatcher->shutdown();
332 }
333
334 if( m_bDestructionEnabled &&
335 (!m_pImpl->xMailDispatcher.is() ||
336 !m_pImpl->xMailDispatcher->isRunning()))
337 {
338 m_xDialog->response(RET_CANCEL);
339 }
340 else
341 {
342 pTimer->Start();
343 }
344}
345
346IMPL_STATIC_LINK( SwSendMailDialog, StopSendMails, void*, p, void )
347{
348 SwSendMailDialog* pDialog = static_cast<SwSendMailDialog*>(p);
349 if(pDialog->m_pImpl->xMailDispatcher.is() &&
350 pDialog->m_pImpl->xMailDispatcher->isStarted())
351 {
352 pDialog->m_pImpl->xMailDispatcher->stop();
353 pDialog->m_xStop->set_label(pDialog->m_sContinue);
354 pDialog->m_xPaused->show();
355 }
356}
357
359{
360 if(!m_pConfigItem)
361 {
362 OSL_FAIL("config item not set");
363 return;
364 }
365 auto xWait(std::make_unique<weld::WaitObject>(m_xDialog.get()));
366 //get a mail server connection
367 uno::Reference< mail::XSmtpService > xSmtpServer =
369 m_pImpl->xConnectedInMailService,
370 OUString(), OUString(), m_xDialog.get());
371 bool bIsLoggedIn = xSmtpServer.is() && xSmtpServer->isConnected();
372 xWait.reset();
373 if(!bIsLoggedIn)
374 {
375 OSL_FAIL("create error message");
376 return;
377 }
378 m_pImpl->xMailDispatcher.set( new MailDispatcher(xSmtpServer));
379 IterateMails();
380 m_pImpl->xMailListener = new SwMailDispatcherListener_Impl(*this);
381 m_pImpl->xMailDispatcher->addListener(m_pImpl->xMailListener);
382 if(!m_bCancel)
383 {
384 m_pImpl->xMailDispatcher->start();
385 }
386}
387
389{
390 const SwMailDescriptor* pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
391 while( pCurrentMailDescriptor )
392 {
393 if (!SwMailMergeHelper::CheckMailAddress( pCurrentMailDescriptor->sEMail))
394 {
395 OUString sMessage = m_sSendingTo;
396 m_xStatus->append();
397 m_xStatus->set_image(m_nProcessedCount, RID_BMP_FORMULA_CANCEL, 0);
398 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", pCurrentMailDescriptor->sEMail), 1);
403 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
404 continue;
405 }
408 pMessage->setReplyToAddress(m_pConfigItem->GetMailReplyTo());
409 pMessage->addRecipient( pCurrentMailDescriptor->sEMail );
410 pMessage->SetSenderName( m_pConfigItem->GetMailDisplayName() );
411 pMessage->SetSenderAddress( m_pConfigItem->GetMailAddress() );
412 if(!pCurrentMailDescriptor->sAttachmentURL.isEmpty())
413 {
414 mail::MailAttachment aAttach;
415 aAttach.Data =
417 pCurrentMailDescriptor->sAttachmentURL,
418 pCurrentMailDescriptor->sAttachmentName,
419 pCurrentMailDescriptor->sMimeType );
420 aAttach.ReadableName = pCurrentMailDescriptor->sAttachmentName;
421 pMessage->addAttachment( aAttach );
422 }
423 pMessage->setSubject( pCurrentMailDescriptor->sSubject );
424 uno::Reference< datatransfer::XTransferable> xBody =
426 pCurrentMailDescriptor->sBodyContent,
427 pCurrentMailDescriptor->sBodyMimeType);
428 pMessage->setBody( xBody );
429
430 //CC and BCC are tokenized by ';'
431 if(!pCurrentMailDescriptor->sCC.isEmpty())
432 {
433 sal_Int32 nPos = 0;
434 do
435 {
436 OUString sTmp = pCurrentMailDescriptor->sCC.getToken( 0, ';', nPos );
437 if( !sTmp.isEmpty() )
438 pMessage->addCcRecipient( sTmp );
439 }
440 while (nPos >= 0);
441 }
442 if(!pCurrentMailDescriptor->sBCC.isEmpty())
443 {
444 sal_Int32 nPos = 0;
445 do
446 {
447 OUString sTmp = pCurrentMailDescriptor->sBCC.getToken( 0, ';', nPos );
448 if( !sTmp.isEmpty() )
449 pMessage->addBccRecipient( sTmp );
450 }
451 while (nPos >= 0);
452 }
453 m_pImpl->xMailDispatcher->enqueueMailMessage( pMessage );
454 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
455 }
457}
458
459void SwSendMailDialog::StartSend(sal_Int32 nExpectedCount)
460{
462 StartSendMails ), this );
463 m_nExpectedCount = nExpectedCount > 0 ? nExpectedCount : 1;
464}
465
466void SwSendMailDialog::DocumentSent( uno::Reference< mail::XMailMessage> const & xMessage,
467 bool bResult,
468 const OUString* pError )
469{
470 //sending should stop on send errors, except after last error - it will stop in AllMailsSent
471 if (pError && m_nProcessedCount + 1 < m_nExpectedCount &&
472 m_pImpl->xMailDispatcher.is() && m_pImpl->xMailDispatcher->isStarted())
473 {
475 StopSendMails ), this );
476 }
477 OUString sInsertImg(bResult ? OUString(RID_BMP_FORMULA_APPLY) : OUString(RID_BMP_FORMULA_CANCEL));
478
479 OUString sMessage = m_sSendingTo;
480 m_xStatus->append();
481 m_xStatus->set_image(m_nProcessedCount, sInsertImg, 0);
482 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", xMessage->getRecipients()[0]), 1);
483 m_xStatus->set_text(m_nProcessedCount, bResult ? m_sCompleted : m_sFailed, 2);
485 if(!bResult)
487
489
490 if (pError)
491 {
492 SwSendWarningBox_Impl aDlg(m_xDialog.get(), *pError);
493 aDlg.run();
494 }
495}
496
498{
499 OUString sStatus( m_sTransferStatus );
500 sStatus = sStatus.replaceFirst("%1", OUString::number(m_nProcessedCount) );
501 sStatus = sStatus.replaceFirst("%2", OUString::number(m_nExpectedCount));
502 m_xTransferStatus->set_label(sStatus);
503
504 sStatus = m_sErrorStatus.replaceFirst("%1", OUString::number(m_nErrorCount) );
505 m_xErrorStatus->set_label(sStatus);
506
507 if (!m_pImpl->aDescriptors.empty())
508 {
509 assert(m_nExpectedCount && "div-by-zero");
510 m_xProgressBar->set_percentage(m_nProcessedCount * 100 / m_nExpectedCount);
511 }
512 else
513 m_xProgressBar->set_percentage(0);
514}
515
517{
519 {
520 m_xStop->set_sensitive(false);
521 m_xCancel->set_label(m_sClose);
522 // Leave open if some kind of error occurred
523 if (m_nErrorCount == 0)
524 {
525 m_xDialog->hide();
526 m_xDialog->response(RET_CANCEL);
527 }
528 }
529}
530
531/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
Reference< XExecutableDialog > m_xDialog
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
MailDispatcher listener interface.
A MailDispatcher should be used for sending a bunch a mail messages asynchronously.
constexpr tools::Long Height() const
constexpr tools::Long Width() const
OUString const & GetMailAddress() const
OUString const & GetMailDisplayName() const
bool IsMailReplyTo() const
OUString const & GetMailReplyTo() const
bool IsOutputToLetter() const
SwMailMergeOutputTypePage(weld::Container *pPage, SwMailMergeWizard *pWizard)
virtual ~SwMailMergeOutputTypePage() override
std::unique_ptr< weld::RadioButton > m_xLetterRB
std::unique_ptr< weld::RadioButton > m_xMailRB
SwMailMergeWizard * m_pWizard
SwMailMergeConfigItem & GetConfigItem()
void StartSend(sal_Int32 nExpectedCount)
SwMailMergeConfigItem * m_pConfigItem
std::unique_ptr< weld::Label > m_xPaused
std::unique_ptr< weld::Label > m_xTransferStatus
std::unique_ptr< SwSendMailDialog_Impl > m_pImpl
void AddDocument(SwMailDescriptor const &rDesc)
SwSendMailDialog(weld::Window *pParent, SwMailMergeConfigItem &)
std::unique_ptr< weld::TreeView > m_xStatus
std::unique_ptr< weld::ProgressBar > m_xProgressBar
sal_Int32 m_nProcessedCount
void DocumentSent(css::uno::Reference< css::mail::XMailMessage > const &xMessage, bool bResult, const OUString *pError)
std::unique_ptr< weld::Button > m_xCancel
std::unique_ptr< weld::Label > m_xErrorStatus
virtual ~SwSendMailDialog() override
std::unique_ptr< weld::Button > m_xStop
sal_Int32 m_nExpectedCount
void SetPriority(TaskPriority ePriority)
std::shared_ptr< weld::Dialog > m_xDialog
void * p
sal_uInt16 nPos
IMPL_LINK_NOARG(SwMailMergeOutputTypePage, TypeHdl_Impl, weld::Toggleable &, void)
IMPL_STATIC_LINK(SwSendMailDialog, StartSendMails, void *, pDialog, void)
IMPL_LINK(SwSendMailDialog, StopHdl_Impl, weld::Button &, rButton, void)
bool UCB_DeleteFile(const OUString &rURL)
Definition: swunohelper.cxx:59
uno::Reference< mail::XSmtpService > ConnectToSmtpServer(SwMailMergeConfigItem const &rConfigItem, uno::Reference< mail::XMailService > &rxInMailService, const OUString &rInMailServerPassword, const OUString &rOutMailServerPassword, weld::Window *pDialogParentWindow)
bool CheckMailAddress(std::u16string_view aMailAddress)
OUString sMessage
std::recursive_mutex aDescriptorMutex
uno::Reference< mail::XMailService > xConnectedInMailService
::rtl::Reference< MailDispatcher > xMailDispatcher
std::vector< SwMailDescriptor > aDescriptors
const SwMailDescriptor * GetNextDescriptor()
::rtl::Reference< IMailDispatcherListener > xMailListener
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:165
RET_CANCEL