xref: /haiku/src/kits/app/MessageRunner.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright 2001-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold (bonefish@users.sf.net)
7  */
8 
9 
10 #include <Application.h>
11 #include <AppMisc.h>
12 #include <MessageRunner.h>
13 #include <RegistrarDefs.h>
14 #include <Roster.h>
15 #include <RosterPrivate.h>
16 
17 using namespace BPrivate;
18 
19 
20 // constructor
21 /*!	\brief Creates and initializes a new BMessageRunner.
22 
23 	The target for replies to the delivered message(s) is \c be_app_messenger.
24 
25 	The success of the initialization can (and should) be asked for via
26 	InitCheck(). This object will not take ownership of the \a message, you
27 	may freely change or delete it after creation.
28 
29 	\note As soon as the last message has been sent, the message runner
30 		  becomes unusable. InitCheck() will still return \c B_OK, but
31 		  SetInterval(), SetCount() and GetInfo() will fail.
32 
33 	\param target Target of the message(s).
34 	\param message The message to be sent to the target.
35 	\param interval Period of time before the first message is sent and
36 		   between messages (if more than one shall be sent) in microseconds.
37 	\param count Specifies how many times the message shall be sent.
38 		   A value less than \c 0 for an unlimited number of repetitions.
39 */
40 BMessageRunner::BMessageRunner(BMessenger target, const BMessage *message,
41 							   bigtime_t interval, int32 count)
42 	: fToken(-1)
43 {
44 	_InitData(target, message, interval, count, be_app_messenger);
45 }
46 
47 // constructor
48 /*!	\brief Creates and initializes a new BMessageRunner.
49 
50 	This constructor version additionally allows to specify the target for
51 	replies to the delivered message(s).
52 
53 	The success of the initialization can (and should) be asked for via
54 	InitCheck(). This object will not take ownership of the \a message, you
55 	may freely change or delete it after creation.
56 
57 	\note As soon as the last message has been sent, the message runner
58 		  becomes unusable. InitCheck() will still return \c B_OK, but
59 		  SetInterval(), SetCount() and GetInfo() will fail.
60 
61 	\param target Target of the message(s).
62 	\param message The message to be sent to the target.
63 	\param interval Period of time before the first message is sent and
64 		   between messages (if more than one shall be sent) in microseconds.
65 	\param count Specifies how many times the message shall be sent.
66 		   A value less than \c 0 for an unlimited number of repetitions.
67 	\param replyTo Target replies to the delivered message(s) shall be sent to.
68 */
69 BMessageRunner::BMessageRunner(BMessenger target, const BMessage *message,
70 							   bigtime_t interval, int32 count,
71 							   BMessenger replyTo)
72 	: fToken(-1)
73 {
74 	_InitData(target, message, interval, count, replyTo);
75 }
76 
77 
78 /*!	\brief Frees all resources associated with the object.
79 */
80 BMessageRunner::~BMessageRunner()
81 {
82 	if (fToken < B_OK)
83 		return;
84 
85 	// compose the request message
86 	BMessage request(B_REG_UNREGISTER_MESSAGE_RUNNER);
87 	status_t error = request.AddInt32("token", fToken);
88 
89 	// send the request
90 	BMessage reply;
91 	if (error == B_OK)
92 		error = BRoster::Private().SendTo(&request, &reply, false);
93 
94 	// ignore the reply, we can't do anything anyway
95 }
96 
97 // InitCheck
98 /*!	\brief Returns the status of the initialization.
99 
100 	\note As soon as the last message has been sent, the message runner
101 		  becomes unusable. InitCheck() will still return \c B_OK, but
102 		  SetInterval(), SetCount() and GetInfo() will fail.
103 
104 	\return \c B_OK, if the object is properly initialized, an error code
105 			otherwise.
106 */
107 status_t
108 BMessageRunner::InitCheck() const
109 {
110 	return fToken >= 0 ? B_OK : fToken;
111 }
112 
113 // SetInterval
114 /*!	\brief Sets the interval of time between messages.
115 	\param interval The new interval in microseconds.
116 	\return
117 	- \c B_OK: Everything went fine.
118 	- \c B_NO_INIT: The message runner is not properly initialized.
119 	- \c B_BAD_VALUE: \a interval is \c 0 or negative, or the message runner
120 	  has already sent all messages to be sent and has become unusable.
121 */
122 status_t
123 BMessageRunner::SetInterval(bigtime_t interval)
124 {
125 	return _SetParams(true, interval, false, 0);
126 }
127 
128 // SetCount
129 /*!	\brief Sets the number of times message shall be sent.
130 	\param count Specifies how many times the message shall be sent.
131 		   A value less than \c 0 for an unlimited number of repetitions.
132 	- \c B_BAD_VALUE: The message runner has already sent all messages to be
133 	  sent and has become unusable.
134 	\return
135 	- \c B_OK: Everything went fine.
136 	- \c B_NO_INIT: The message runner is not properly initialized.
137 */
138 status_t
139 BMessageRunner::SetCount(int32 count)
140 {
141 	return _SetParams(false, 0, true, count);
142 }
143 
144 // GetInfo
145 /*!	\brief Returns the time interval between two messages and the number of
146 		   times the message has still to be sent.
147 
148 	Both parameters (\a interval and \a count) may be \c NULL.
149 
150 	\param interval Pointer to a pre-allocated bigtime_t variable to be set
151 		   to the time interval. May be \c NULL.
152 	\param count Pointer to a pre-allocated int32 variable to be set
153 		   to the number of times the message has still to be sent.
154 		   May be \c NULL.
155 	\return
156 	- \c B_OK: Everything went fine.
157 	- \c B_BAD_VALUE: The message runner is not longer valid. All the
158 	  messages that had to be sent have already been sent.
159 */
160 status_t
161 BMessageRunner::GetInfo(bigtime_t *interval, int32 *count) const
162 {
163 	status_t error =  (fToken >= 0 ? B_OK : B_BAD_VALUE);
164 	// compose the request message
165 	BMessage request(B_REG_GET_MESSAGE_RUNNER_INFO);
166 	if (error == B_OK)
167 		error = request.AddInt32("token", fToken);
168 	// send the request
169 	BMessage reply;
170 	if (error == B_OK)
171 		error = BRoster::Private().SendTo(&request, &reply, false);
172 	// evaluate the reply
173 	if (error == B_OK) {
174 		if (reply.what == B_REG_SUCCESS) {
175 			// count
176 			int32 _count;
177 			if (reply.FindInt32("count", &_count) == B_OK) {
178 				if (count)
179 					*count = _count;
180 			} else
181 				error = B_ERROR;
182 			// interval
183 			bigtime_t _interval;
184 			if (reply.FindInt64("interval", &_interval) == B_OK) {
185 				if (interval)
186 					*interval = _interval;
187 			} else
188 				error = B_ERROR;
189 		} else {
190 			if (reply.FindInt32("error", &error) != B_OK)
191 				error = B_ERROR;
192 		}
193 	}
194 	return error;
195 }
196 
197 
198 /*!	\brief Creates and initializes a detached BMessageRunner.
199 
200 	You cannot alter the runner after the creation, and it will be deleted
201 	automatically once it is done.
202 	The target for replies to the delivered message(s) is \c be_app_messenger.
203 
204 	\param target Target of the message(s).
205 	\param message The message to be sent to the target.
206 	\param interval Period of time before the first message is sent and
207 		   between messages (if more than one shall be sent) in microseconds.
208 	\param count Specifies how many times the message shall be sent.
209 		   A value less than \c 0 for an unlimited number of repetitions.
210 */
211 /*static*/ status_t
212 BMessageRunner::StartSending(BMessenger target, const BMessage *message,
213 	bigtime_t interval, int32 count)
214 {
215 	int32 token = _RegisterRunner(target, message, interval, count, true,
216 		be_app_messenger);
217 	return token >= B_OK ? B_OK : token;
218 }
219 
220 
221 /*!	\brief Creates and initializes a detached BMessageRunner.
222 
223 	You cannot alter the runner after the creation, and it will be deleted
224 	automatically once it is done.
225 
226 	\param target Target of the message(s).
227 	\param message The message to be sent to the target.
228 	\param interval Period of time before the first message is sent and
229 		   between messages (if more than one shall be sent) in microseconds.
230 	\param count Specifies how many times the message shall be sent.
231 		   A value less than \c 0 for an unlimited number of repetitions.
232 	\param replyTo Target replies to the delivered message(s) shall be sent to.
233 */
234 /*static*/ status_t
235 BMessageRunner::StartSending(BMessenger target, const BMessage *message,
236 	bigtime_t interval, int32 count, BMessenger replyTo)
237 {
238 	int32 token = _RegisterRunner(target, message, interval, count, true, replyTo);
239 	return token >= B_OK ? B_OK : token;
240 }
241 
242 
243 // FBC
244 void BMessageRunner::_ReservedMessageRunner1() {}
245 void BMessageRunner::_ReservedMessageRunner2() {}
246 void BMessageRunner::_ReservedMessageRunner3() {}
247 void BMessageRunner::_ReservedMessageRunner4() {}
248 void BMessageRunner::_ReservedMessageRunner5() {}
249 void BMessageRunner::_ReservedMessageRunner6() {}
250 
251 // copy constructor
252 /*!	\brief Privatized copy constructor to prevent usage.
253 */
254 BMessageRunner::BMessageRunner(const BMessageRunner &)
255 	: fToken(-1)
256 {
257 }
258 
259 // =
260 /*!	\brief Privatized assignment operator to prevent usage.
261 */
262 BMessageRunner &
263 BMessageRunner::operator=(const BMessageRunner &)
264 {
265 	return *this;
266 }
267 
268 
269 /*!	\brief Initializes the BMessageRunner.
270 
271 	The success of the initialization can (and should) be asked for via
272 	InitCheck().
273 
274 	\note As soon as the last message has been sent, the message runner
275 		  becomes unusable. InitCheck() will still return \c B_OK, but
276 		  SetInterval(), SetCount() and GetInfo() will fail.
277 
278 	\param target Target of the message(s).
279 	\param message The message to be sent to the target.
280 	\param interval Period of time before the first message is sent and
281 		   between messages (if more than one shall be sent) in microseconds.
282 	\param count Specifies how many times the message shall be sent.
283 		   A value less than \c 0 for an unlimited number of repetitions.
284 	\param replyTo Target replies to the delivered message(s) shall be sent to.
285 */
286 void
287 BMessageRunner::_InitData(BMessenger target, const BMessage *message,
288 	bigtime_t interval, int32 count, BMessenger replyTo)
289 {
290 	fToken = _RegisterRunner(target, message, interval, count, false, replyTo);
291 }
292 
293 
294 /*!	\brief Registers the BMessageRunner in the registrar.
295 
296 	\param target Target of the message(s).
297 	\param message The message to be sent to the target.
298 	\param interval Period of time before the first message is sent and
299 		   between messages (if more than one shall be sent) in microseconds.
300 	\param count Specifies how many times the message shall be sent.
301 		   A value less than \c 0 for an unlimited number of repetitions.
302 	\param replyTo Target replies to the delivered message(s) shall be sent to.
303 
304 	\return The token the message runner is registered with, or the error code
305 		while trying to register it.
306 */
307 /*static*/ int32
308 BMessageRunner::_RegisterRunner(BMessenger target, const BMessage *message,
309 	bigtime_t interval, int32 count, bool detach, BMessenger replyTo)
310 {
311 	status_t error = B_OK;
312 	if (message == NULL || count == 0 || (count < 0 && detach))
313 		error = B_BAD_VALUE;
314 
315 	// compose the request message
316 	BMessage request(B_REG_REGISTER_MESSAGE_RUNNER);
317 	if (error == B_OK)
318 		error = request.AddInt32("team", BPrivate::current_team());
319 	if (error == B_OK)
320 		error = request.AddMessenger("target", target);
321 	if (error == B_OK)
322 		error = request.AddMessage("message", message);
323 	if (error == B_OK)
324 		error = request.AddInt64("interval", interval);
325 	if (error == B_OK)
326 		error = request.AddInt32("count", count);
327 	if (error == B_OK)
328 		error = request.AddMessenger("reply_target", replyTo);
329 
330 	// send the request
331 	BMessage reply;
332 	if (error == B_OK)
333 		error = BRoster::Private().SendTo(&request, &reply, false);
334 
335 	int32 token;
336 
337 	// evaluate the reply
338 	if (error == B_OK) {
339 		if (reply.what == B_REG_SUCCESS) {
340 			if (reply.FindInt32("token", &token) != B_OK)
341 				error = B_ERROR;
342 		} else {
343 			if (reply.FindInt32("error", &error) != B_OK)
344 				error = B_ERROR;
345 		}
346 	}
347 
348 	if (error == B_OK)
349 		return token;
350 
351 	return error;
352 }
353 
354 
355 /*!	\brief Sets the message runner's interval and count parameters.
356 
357 	The parameters \a resetInterval and \a resetCount specify whether
358 	the interval or the count parameter respectively shall be reset.
359 
360 	At least one parameter must be set, otherwise the methods returns
361 	\c B_BAD_VALUE.
362 
363 	\param resetInterval \c true, if the interval shall be reset, \c false
364 		   otherwise -- then \a interval is ignored.
365 	\param interval The new interval in microseconds.
366 	\param resetCount \c true, if the count shall be reset, \c false
367 		   otherwise -- then \a count is ignored.
368 	\param count Specifies how many times the message shall be sent.
369 		   A value less than \c 0 for an unlimited number of repetitions.
370 	\return
371 	- \c B_OK: Everything went fine.
372 	- \c B_BAD_VALUE: The message runner is not longer valid. All the
373 	  messages that had to be sent have already been sent. Or both
374 	  \a resetInterval and \a resetCount are \c false.
375 */
376 status_t
377 BMessageRunner::_SetParams(bool resetInterval, bigtime_t interval,
378 	bool resetCount, int32 count)
379 {
380 	if ((!resetInterval && !resetCount) || fToken < 0)
381 		return B_BAD_VALUE;
382 
383 	// compose the request message
384 	BMessage request(B_REG_SET_MESSAGE_RUNNER_PARAMS);
385 	status_t error = request.AddInt32("token", fToken);
386 	if (error == B_OK && resetInterval)
387 		error = request.AddInt64("interval", interval);
388 	if (error == B_OK && resetCount)
389 		error = request.AddInt32("count", count);
390 
391 	// send the request
392 	BMessage reply;
393 	if (error == B_OK)
394 		error = BRoster::Private().SendTo(&request, &reply, false);
395 
396 	// evaluate the reply
397 	if (error == B_OK) {
398 		if (reply.what != B_REG_SUCCESS) {
399 			if (reply.FindInt32("error", &error) != B_OK)
400 				error = B_ERROR;
401 		}
402 	}
403 	return error;
404 }
405 
406