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