1/*
2 * Copyright 2001-2010 Haiku, Inc. All rights reserved.
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
22BMessageRunner::BMessageRunner(BMessenger target, const BMessage* message,
23	bigtime_t interval, int32 count)
24	:
25	fToken(-1)
26{
27	_InitData(target, message, interval, count, be_app_messenger);
28}
29
30
31BMessageRunner::BMessageRunner(BMessenger target, const BMessage& message,
32	bigtime_t interval, int32 count)
33	:
34	fToken(-1)
35{
36	_InitData(target, &message, interval, count, be_app_messenger);
37}
38
39
40BMessageRunner::BMessageRunner(BMessenger target, const BMessage* message,
41	bigtime_t interval, int32 count, BMessenger replyTo)
42	:
43	fToken(-1)
44{
45	_InitData(target, message, interval, count, replyTo);
46}
47
48
49BMessageRunner::BMessageRunner(BMessenger target, const BMessage& message,
50	bigtime_t interval, int32 count, BMessenger replyTo)
51	:
52	fToken(-1)
53{
54	_InitData(target, &message, interval, count, replyTo);
55}
56
57
58BMessageRunner::~BMessageRunner()
59{
60	if (fToken < B_OK)
61		return;
62
63	// compose the request message
64	BMessage request(B_REG_UNREGISTER_MESSAGE_RUNNER);
65	status_t result = request.AddInt32("token", fToken);
66
67	// send the request
68	BMessage reply;
69	if (result == B_OK)
70		result = BRoster::Private().SendTo(&request, &reply, false);
71
72	// ignore the reply, we can't do anything anyway
73}
74
75
76status_t
77BMessageRunner::InitCheck() const
78{
79	return fToken >= 0 ? B_OK : fToken;
80}
81
82
83status_t
84BMessageRunner::SetInterval(bigtime_t interval)
85{
86	return _SetParams(true, interval, false, 0);
87}
88
89
90status_t
91BMessageRunner::SetCount(int32 count)
92{
93	return _SetParams(false, 0, true, count);
94}
95
96
97status_t
98BMessageRunner::GetInfo(bigtime_t* interval, int32* count) const
99{
100	status_t result =  fToken >= 0 ? B_OK : B_BAD_VALUE;
101
102	// compose the request message
103	BMessage request(B_REG_GET_MESSAGE_RUNNER_INFO);
104	if (result == B_OK)
105		result = request.AddInt32("token", fToken);
106
107	// send the request
108	BMessage reply;
109	if (result == B_OK)
110		result = BRoster::Private().SendTo(&request, &reply, false);
111
112	// evaluate the reply
113	if (result == B_OK) {
114		if (reply.what == B_REG_SUCCESS) {
115			// count
116			int32 _count;
117			if (reply.FindInt32("count", &_count) == B_OK) {
118				if (count != 0)
119					*count = _count;
120			} else
121				result = B_ERROR;
122
123			// interval
124			bigtime_t _interval;
125			if (reply.FindInt64("interval", &_interval) == B_OK) {
126				if (interval != 0)
127					*interval = _interval;
128			} else
129				result = B_ERROR;
130		} else {
131			if (reply.FindInt32("error", &result) != B_OK)
132				result = B_ERROR;
133		}
134	}
135
136	return result;
137}
138
139
140/*static*/ status_t
141BMessageRunner::StartSending(BMessenger target, const BMessage* message,
142	bigtime_t interval, int32 count)
143{
144	int32 token = _RegisterRunner(target, message, interval, count, true,
145		be_app_messenger);
146
147	return token >= B_OK ? B_OK : token;
148}
149
150
151/*static*/ status_t
152BMessageRunner::StartSending(BMessenger target, const BMessage* message,
153	bigtime_t interval, int32 count, BMessenger replyTo)
154{
155	int32 token = _RegisterRunner(target, message, interval, count, true,
156		replyTo);
157
158	return token >= B_OK ? B_OK : token;
159}
160
161
162// FBC
163void BMessageRunner::_ReservedMessageRunner1() {}
164void BMessageRunner::_ReservedMessageRunner2() {}
165void BMessageRunner::_ReservedMessageRunner3() {}
166void BMessageRunner::_ReservedMessageRunner4() {}
167void BMessageRunner::_ReservedMessageRunner5() {}
168void BMessageRunner::_ReservedMessageRunner6() {}
169
170
171#ifdef _BEOS_R5_COMPATIBLE_
172//! Privatized copy constructor to prevent usage.
173BMessageRunner::BMessageRunner(const BMessageRunner &)
174	:
175	fToken(-1)
176{
177}
178
179
180//! Privatized assignment operator to prevent usage.
181BMessageRunner&
182BMessageRunner::operator=(const BMessageRunner&)
183{
184	return* this;
185}
186#endif
187
188
189/*!	Initializes the BMessageRunner.
190
191	The success of the initialization can (and should) be asked for via
192	InitCheck().
193
194	\note As soon as the last message has been sent, the message runner
195	      becomes unusable. InitCheck() will still return \c B_OK, but
196	      SetInterval(), SetCount() and GetInfo() will fail.
197
198	\param target Target of the message(s).
199	\param message The message to be sent to the target.
200	\param interval Period of time before the first message is sent and
201	       between messages (if more than one shall be sent) in microseconds.
202	\param count Specifies how many times the message shall be sent.
203	       A value less than \c 0 for an unlimited number of repetitions.
204	\param replyTo Target replies to the delivered message(s) shall be sent to.
205*/
206void
207BMessageRunner::_InitData(BMessenger target, const BMessage* message,
208	bigtime_t interval, int32 count, BMessenger replyTo)
209{
210	fToken = _RegisterRunner(target, message, interval, count, false, replyTo);
211}
212
213
214/*!	Registers the BMessageRunner in the registrar.
215
216	\param target Target of the message(s).
217	\param message The message to be sent to the target.
218	\param interval Period of time before the first message is sent and
219	       between messages (if more than one shall be sent) in microseconds.
220	\param count Specifies how many times the message shall be sent.
221	       A value less than \c 0 for an unlimited number of repetitions.
222	\param replyTo Target replies to the delivered message(s) shall be sent to.
223
224	\return The token the message runner is registered with, or the error code
225	        while trying to register it.
226*/
227/*static*/ int32
228BMessageRunner::_RegisterRunner(BMessenger target, const BMessage* message,
229	bigtime_t interval, int32 count, bool detach, BMessenger replyTo)
230{
231	status_t result = B_OK;
232	if (message == NULL || count == 0 || (count < 0 && detach))
233		result = B_BAD_VALUE;
234
235	// compose the request message
236	BMessage request(B_REG_REGISTER_MESSAGE_RUNNER);
237	if (result == B_OK)
238		result = request.AddInt32("team", BPrivate::current_team());
239
240	if (result == B_OK)
241		result = request.AddMessenger("target", target);
242
243	if (result == B_OK)
244		result = request.AddMessage("message", message);
245
246	if (result == B_OK)
247		result = request.AddInt64("interval", interval);
248
249	if (result == B_OK)
250		result = request.AddInt32("count", count);
251
252	if (result == B_OK)
253		result = request.AddMessenger("reply_target", replyTo);
254
255	// send the request
256	BMessage reply;
257	if (result == B_OK)
258		result = BRoster::Private().SendTo(&request, &reply, false);
259
260	int32 token;
261
262	// evaluate the reply
263	if (result == B_OK) {
264		if (reply.what == B_REG_SUCCESS) {
265			if (reply.FindInt32("token", &token) != B_OK)
266				result = B_ERROR;
267		} else {
268			if (reply.FindInt32("error", &result) != B_OK)
269				result = B_ERROR;
270		}
271	}
272
273	if (result == B_OK)
274		return token;
275
276	return result;
277}
278
279
280/*!	Sets the message runner's interval and count parameters.
281
282	The parameters \a resetInterval and \a resetCount specify whether
283	the interval or the count parameter respectively shall be reset.
284
285	At least one parameter must be set, otherwise the methods returns
286	\c B_BAD_VALUE.
287
288	\param resetInterval \c true, if the interval shall be reset, \c false
289	       otherwise -- then \a interval is ignored.
290	\param interval The new interval in microseconds.
291	\param resetCount \c true, if the count shall be reset, \c false
292	       otherwise -- then \a count is ignored.
293	\param count Specifies how many times the message shall be sent.
294	       A value less than \c 0 for an unlimited number of repetitions.
295
296	\return A status code.
297	\retval B_OK Everything went fine.
298	\retval B_BAD_VALUE The message runner is not longer valid. All the
299	        messages that had to be sent have already been sent. Or both
300	        \a resetInterval and \a resetCount are \c false.
301*/
302status_t
303BMessageRunner::_SetParams(bool resetInterval, bigtime_t interval,
304	bool resetCount, int32 count)
305{
306	if ((!resetInterval && !resetCount) || fToken < 0)
307		return B_BAD_VALUE;
308
309	// compose the request message
310	BMessage request(B_REG_SET_MESSAGE_RUNNER_PARAMS);
311	status_t result = request.AddInt32("token", fToken);
312	if (result == B_OK && resetInterval)
313		result = request.AddInt64("interval", interval);
314
315	if (result == B_OK && resetCount)
316		result = request.AddInt32("count", count);
317
318	// send the request
319	BMessage reply;
320	if (result == B_OK)
321		result = BRoster::Private().SendTo(&request, &reply, false);
322
323	// evaluate the reply
324	if (result == B_OK) {
325		if (reply.what != B_REG_SUCCESS) {
326			if (reply.FindInt32("error", &result) != B_OK)
327				result = B_ERROR;
328		}
329	}
330
331	return result;
332}
333