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
19using 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*/
41BMessageRunner::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*/
69BMessageRunner::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*/
99BMessageRunner::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*/
129BMessageRunner::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*/
140BMessageRunner::~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*/
167status_t
168BMessageRunner::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*/
182status_t
183BMessageRunner::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*/
198status_t
199BMessageRunner::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*/
220status_t
221BMessageRunner::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
276BMessageRunner::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
299BMessageRunner::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
308void BMessageRunner::_ReservedMessageRunner1() {}
309void BMessageRunner::_ReservedMessageRunner2() {}
310void BMessageRunner::_ReservedMessageRunner3() {}
311void BMessageRunner::_ReservedMessageRunner4() {}
312void BMessageRunner::_ReservedMessageRunner5() {}
313void BMessageRunner::_ReservedMessageRunner6() {}
314
315
316/*!	\brief Privatized copy constructor to prevent usage.
317*/
318BMessageRunner::BMessageRunner(const BMessageRunner &)
319	: fToken(-1)
320{
321}
322
323
324/*!	\brief Privatized assignment operator to prevent usage.
325*/
326BMessageRunner &
327BMessageRunner::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*/
350void
351BMessageRunner::_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
372BMessageRunner::_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*/
440status_t
441BMessageRunner::_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