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 "maildispatcher.hxx"
21 #include "imaildsplistener.hxx"
25 using namespace ::com::sun::star
;
27 typedef std::list
< ::rtl::Reference
<IMailDispatcherListener
> > MailDispatcherListenerContainer_t
;
29 namespace /* private */
31 /* Generic event notifier for started,
32 stopped, and idle events which are
34 class GenericEventNotifier
37 // pointer to virtual function typedef
38 typedef void (IMailDispatcherListener::*GenericNotificationFunc_t
)(::rtl::Reference
<MailDispatcher
>);
41 GenericNotificationFunc_t notification_function
,
42 ::rtl::Reference
<MailDispatcher
> mail_dispatcher
) :
43 notification_function_(notification_function
),
44 mail_dispatcher_(mail_dispatcher
)
47 void operator() (::rtl::Reference
<IMailDispatcherListener
> listener
) const
48 { (listener
.get()->*notification_function_
)(mail_dispatcher_
); }
51 GenericNotificationFunc_t notification_function_
;
52 ::rtl::Reference
<MailDispatcher
> mail_dispatcher_
;
55 class MailDeliveryNotifier
58 MailDeliveryNotifier(::rtl::Reference
<MailDispatcher
> xMailDispatcher
, uno::Reference
<mail::XMailMessage
> message
) :
59 mail_dispatcher_(xMailDispatcher
),
63 void operator() (::rtl::Reference
<IMailDispatcherListener
> listener
) const
64 { listener
->mailDelivered(mail_dispatcher_
, message_
); }
67 ::rtl::Reference
<MailDispatcher
> mail_dispatcher_
;
68 uno::Reference
<mail::XMailMessage
> message_
;
71 class MailDeliveryErrorNotifier
74 MailDeliveryErrorNotifier(
75 ::rtl::Reference
<MailDispatcher
> xMailDispatcher
,
76 uno::Reference
<mail::XMailMessage
> message
,
77 const OUString
& error_message
) :
78 mail_dispatcher_(xMailDispatcher
),
80 error_message_(error_message
)
83 void operator() (::rtl::Reference
<IMailDispatcherListener
> listener
) const
84 { listener
->mailDeliveryError(mail_dispatcher_
, message_
, error_message_
); }
87 ::rtl::Reference
<MailDispatcher
> mail_dispatcher_
;
88 uno::Reference
<mail::XMailMessage
> message_
;
89 OUString error_message_
;
92 } // namespace private
94 MailDispatcher::MailDispatcher(uno::Reference
<mail::XSmtpService
> mailserver
) :
95 mailserver_ (mailserver
),
97 shutdown_requested_(false)
99 wakening_call_
.reset();
100 mail_dispatcher_active_
.reset();
103 throw uno::RuntimeException();
105 // wait until the mail dispatcher thread is really alive
106 // and has aquired a reference to this instance of the
108 mail_dispatcher_active_
.wait();
111 MailDispatcher::~MailDispatcher()
115 void MailDispatcher::enqueueMailMessage(uno::Reference
<mail::XMailMessage
> message
)
117 ::osl::MutexGuard
thread_status_guard(thread_status_mutex_
);
118 ::osl::MutexGuard
message_container_guard(message_container_mutex_
);
120 OSL_PRECOND(!shutdown_requested_
, "MailDispatcher thread is shuting down already");
122 messages_
.push_back(message
);
124 wakening_call_
.set();
127 uno::Reference
<mail::XMailMessage
> MailDispatcher::dequeueMailMessage()
129 ::osl::MutexGuard
guard(message_container_mutex_
);
130 uno::Reference
<mail::XMailMessage
> message
;
131 if(!messages_
.empty())
133 message
= messages_
.front();
134 messages_
.pop_front();
139 void MailDispatcher::start()
141 OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
143 ::osl::ClearableMutexGuard
thread_status_guard(thread_status_mutex_
);
145 OSL_PRECOND(!shutdown_requested_
, "MailDispatcher thread is shuting down already");
147 if (!shutdown_requested_
)
150 wakening_call_
.set();
151 thread_status_guard
.clear();
153 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
154 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), GenericEventNotifier(&IMailDispatcherListener::started
, this));
158 void MailDispatcher::stop()
160 OSL_PRECOND(isStarted(), "MailDispatcher not started!");
162 ::osl::ClearableMutexGuard
thread_status_guard(thread_status_mutex_
);
164 OSL_PRECOND(!shutdown_requested_
, "MailDispatcher thread is shuting down already");
166 if (!shutdown_requested_
)
169 wakening_call_
.reset();
170 thread_status_guard
.clear();
172 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
173 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), GenericEventNotifier(&IMailDispatcherListener::stopped
, this));
177 void MailDispatcher::shutdown()
179 ::osl::MutexGuard
thread_status_guard(thread_status_mutex_
);
181 OSL_PRECOND(!shutdown_requested_
, "MailDispatcher thread is shuting down already");
183 shutdown_requested_
= true;
184 wakening_call_
.set();
187 bool MailDispatcher::isStarted() const
192 void MailDispatcher::addListener(::rtl::Reference
<IMailDispatcherListener
> listener
)
194 OSL_PRECOND(!shutdown_requested_
, "MailDispatcher thread is shuting down already");
196 ::osl::MutexGuard
guard(listener_container_mutex_
);
197 listeners_
.push_back(listener
);
200 std::list
< ::rtl::Reference
<IMailDispatcherListener
> > MailDispatcher::cloneListener()
202 ::osl::MutexGuard
guard(listener_container_mutex_
);
206 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference
<mail::XMailMessage
> message
)
210 mailserver_
->sendMailMessage(message
);
211 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
212 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), MailDeliveryNotifier(this, message
));
214 catch (const mail::MailException
& ex
)
216 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
217 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), MailDeliveryErrorNotifier(this, message
, ex
.Message
));
219 catch (const uno::RuntimeException
& ex
)
221 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
222 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), MailDeliveryErrorNotifier(this, message
, ex
.Message
));
226 void MailDispatcher::run()
228 // aquire a self reference in order to avoid race
229 // conditions. The last client of this class must
230 // call shutdown before releasing his last reference
231 // to this class in order to shutdown this thread
232 // which will release his (the very last reference
233 // to the class and so force their destruction
234 m_xSelfReference
= this;
236 // signal that the mail dispatcher thread is now alive
237 mail_dispatcher_active_
.set();
241 wakening_call_
.wait();
243 ::osl::ClearableMutexGuard
thread_status_guard(thread_status_mutex_
);
244 if (shutdown_requested_
)
247 ::osl::ClearableMutexGuard
message_container_guard(message_container_mutex_
);
249 if (messages_
.size())
251 thread_status_guard
.clear();
252 uno::Reference
<mail::XMailMessage
> message
= messages_
.front();
253 messages_
.pop_front();
254 message_container_guard
.clear();
255 sendMailMessageNotifyListener(message
);
257 else // idle - put ourself to sleep
259 wakening_call_
.reset();
260 message_container_guard
.clear();
261 thread_status_guard
.clear();
262 MailDispatcherListenerContainer_t
listeners_cloned(cloneListener());
263 std::for_each(listeners_cloned
.begin(), listeners_cloned
.end(), GenericEventNotifier(&IMailDispatcherListener::idle
, this));
268 void MailDispatcher::onTerminated()
270 //keep the reference until the end of onTerminated() because of the call order in the
271 //_threadFunc() from osl/thread.hxx
272 m_xSelfReference
= 0;
275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */