1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include "maildispatcher.hxx"
27 #include "imaildsplistener.hxx"
28 
29 #include <algorithm>
30 
31 using namespace ::com::sun::star;
32 using ::rtl::OUString;
33 
34 typedef std::list< uno::Reference<mail::XMailMessage> > MailMessageContainer_t;
35 typedef std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t;
36 
37 namespace /* private */
38 {
39     /* Generic event notifier for started,
40        stopped, and idle events which are
41        very similary */
42     class GenericEventNotifier
43     {
44     public:
45         // pointer to virtual function typedef
46         typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference<MailDispatcher>);
47 
GenericEventNotifier(GenericNotificationFunc_t notification_function,::rtl::Reference<MailDispatcher> mail_dispatcher)48         GenericEventNotifier(
49             GenericNotificationFunc_t notification_function,
50             ::rtl::Reference<MailDispatcher> mail_dispatcher) :
51             notification_function_(notification_function),
52             mail_dispatcher_(mail_dispatcher)
53         {}
54 
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const55         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
56         { (listener.get()->*notification_function_)(mail_dispatcher_); }
57 
58     private:
59         GenericNotificationFunc_t notification_function_;
60         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
61     };
62 
63     class MailDeliveryNotifier
64     {
65     public:
MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher,uno::Reference<mail::XMailMessage> message)66         MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher, uno::Reference<mail::XMailMessage> message) :
67             mail_dispatcher_(xMailDispatcher),
68             message_(message)
69         {}
70 
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const71         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
72         { listener->mailDelivered(mail_dispatcher_, message_); }
73 
74     private:
75         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
76         uno::Reference<mail::XMailMessage> message_;
77     };
78 
79     class MailDeliveryErrorNotifier
80     {
81     public:
MailDeliveryErrorNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher,uno::Reference<mail::XMailMessage> message,const::rtl::OUString & error_message)82         MailDeliveryErrorNotifier(
83             ::rtl::Reference<MailDispatcher> xMailDispatcher,
84             uno::Reference<mail::XMailMessage> message,
85             const ::rtl::OUString& error_message) :
86             mail_dispatcher_(xMailDispatcher),
87             message_(message),
88             error_message_(error_message)
89         {}
90 
operator ()(::rtl::Reference<IMailDispatcherListener> listener) const91         void operator() (::rtl::Reference<IMailDispatcherListener> listener) const
92         { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); }
93 
94     private:
95         ::rtl::Reference<MailDispatcher> mail_dispatcher_;
96         uno::Reference<mail::XMailMessage> message_;
97         ::rtl::OUString error_message_;
98     };
99 
100 } // namespace private
101 
102 
MailDispatcher(uno::Reference<mail::XSmtpService> mailserver)103 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> mailserver) :
104     mailserver_ (mailserver),
105     run_(false),
106     shutdown_requested_(false)
107 {
108     wakening_call_.reset();
109     mail_dispatcher_active_.reset();
110 
111     if (!create())
112         throw uno::RuntimeException();
113 
114     // wait until the mail dispatcher thread is really alive
115     // and has aquired a reference to this instance of the
116     // class
117     mail_dispatcher_active_.wait();
118 }
119 
~MailDispatcher()120 MailDispatcher::~MailDispatcher()
121 {
122 }
123 
enqueueMailMessage(uno::Reference<mail::XMailMessage> message)124 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> message)
125 {
126     ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
127     ::osl::MutexGuard message_container_guard(message_container_mutex_);
128 
129     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
130 
131     messages_.push_back(message);
132     if (run_)
133         wakening_call_.set();
134 }
135 
dequeueMailMessage()136 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage()
137 {
138     ::osl::MutexGuard guard(message_container_mutex_);
139     uno::Reference<mail::XMailMessage> message;
140     if(!messages_.empty())
141     {
142         message = messages_.front();
143         messages_.pop_front();
144     }
145     return message;
146 }
147 
start()148 void MailDispatcher::start()
149 {
150     OSL_PRECOND(!isStarted(), "MailDispatcher is already started!");
151 
152     ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
153 
154     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
155 
156     if (!shutdown_requested_)
157     {
158         run_ = true;
159         wakening_call_.set();
160         thread_status_guard.clear();
161 
162         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
163         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::started, this));
164     }
165 }
166 
stop()167 void MailDispatcher::stop()
168 {
169     OSL_PRECOND(isStarted(), "MailDispatcher not started!");
170 
171     ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
172 
173     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
174 
175     if (!shutdown_requested_)
176     {
177         run_ = false;
178         wakening_call_.reset();
179         thread_status_guard.clear();
180 
181         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
182         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::stopped, this));
183     }
184 }
185 
shutdown()186 void MailDispatcher::shutdown()
187 {
188     ::osl::MutexGuard thread_status_guard(thread_status_mutex_);
189 
190     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
191 
192     shutdown_requested_ = true;
193     wakening_call_.set();
194 }
195 
isStarted() const196 bool MailDispatcher::isStarted() const
197 {
198     return run_;
199 }
200 
addListener(::rtl::Reference<IMailDispatcherListener> listener)201 void MailDispatcher::addListener(::rtl::Reference<IMailDispatcherListener> listener)
202 {
203     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
204 
205     ::osl::MutexGuard guard(listener_container_mutex_);
206     listeners_.push_back(listener);
207 }
208 
removeListener(::rtl::Reference<IMailDispatcherListener> listener)209 void MailDispatcher::removeListener(::rtl::Reference<IMailDispatcherListener> listener)
210 {
211     OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already");
212 
213     ::osl::MutexGuard guard(listener_container_mutex_);
214     listeners_.remove(listener);
215 }
216 
cloneListener()217 std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener()
218 {
219     ::osl::MutexGuard guard(listener_container_mutex_);
220     return listeners_;
221 }
222 
sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message)223 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message)
224 {
225     try
226     {
227         mailserver_->sendMailMessage(message);
228         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
229         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryNotifier(this, message));
230     }
231     catch (mail::MailException& ex)
232     {
233         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
234         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
235     }
236     catch (uno::RuntimeException& ex)
237     {
238         MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
239         std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message));
240     }
241 }
242 
run()243 void MailDispatcher::run()
244 {
245     // aquire a self reference in order to avoid race
246     // conditions. The last client of this class must
247     // call shutdown before releasing his last reference
248     // to this class in order to shutdown this thread
249     // which will release his (the very last reference
250     // to the class and so force their destruction
251     m_xSelfReference = this;
252 
253     // signal that the mail dispatcher thread is now alive
254     mail_dispatcher_active_.set();
255 
256     for(;;)
257     {
258         wakening_call_.wait();
259 
260         ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_);
261         if (shutdown_requested_)
262            break;
263 
264         ::osl::ClearableMutexGuard message_container_guard(message_container_mutex_);
265 
266         if (messages_.size())
267         {
268             thread_status_guard.clear();
269             uno::Reference<mail::XMailMessage> message = messages_.front();
270             messages_.pop_front();
271             message_container_guard.clear();
272             sendMailMessageNotifyListener(message);
273         }
274         else // idle - put ourself to sleep
275         {
276             wakening_call_.reset();
277             message_container_guard.clear();
278             thread_status_guard.clear();
279             MailDispatcherListenerContainer_t listeners_cloned(cloneListener());
280             std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::idle, this));
281         }
282     } // end for        SSH ALI
283 }
284 /*-- 27.08.2004 12:04:46---------------------------------------------------
285 
286   -----------------------------------------------------------------------*/
onTerminated()287 void MailDispatcher::onTerminated()
288 {
289     //keep the reference until the end of onTerminated() because of the call order in the
290     //_threadFunc() from osl/thread.hxx
291     m_xSelfReference = 0;
292 }
293