xref: /haiku/src/kits/app/MessageRunner.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
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 			reply.FindInt32("error", &error);
191 	}
192 	return error;
193 }
194 
195 
196 /*!	\brief Creates and initializes a detached BMessageRunner.
197 
198 	You cannot alter the runner after the creation, and it will be deleted
199 	automatically once it is done.
200 	The target for replies to the delivered message(s) is \c be_app_messenger.
201 
202 	\param target Target of the message(s).
203 	\param message The message to be sent to the target.
204 	\param interval Period of time before the first message is sent and
205 		   between messages (if more than one shall be sent) in microseconds.
206 	\param count Specifies how many times the message shall be sent.
207 		   A value less than \c 0 for an unlimited number of repetitions.
208 */
209 /*static*/ status_t
210 BMessageRunner::StartSending(BMessenger target, const BMessage *message,
211 	bigtime_t interval, int32 count)
212 {
213 	int32 token = _RegisterRunner(target, message, interval, count, true,
214 		be_app_messenger);
215 	return token >= B_OK ? B_OK : token;
216 }
217 
218 
219 /*!	\brief Creates and initializes a detached BMessageRunner.
220 
221 	You cannot alter the runner after the creation, and it will be deleted
222 	automatically once it is done.
223 
224 	\param target Target of the message(s).
225 	\param message The message to be sent to the target.
226 	\param interval Period of time before the first message is sent and
227 		   between messages (if more than one shall be sent) in microseconds.
228 	\param count Specifies how many times the message shall be sent.
229 		   A value less than \c 0 for an unlimited number of repetitions.
230 	\param replyTo Target replies to the delivered message(s) shall be sent to.
231 */
232 /*static*/ status_t
233 BMessageRunner::StartSending(BMessenger target, const BMessage *message,
234 	bigtime_t interval, int32 count, BMessenger replyTo)
235 {
236 	int32 token = _RegisterRunner(target, message, interval, count, true, replyTo);
237 	return token >= B_OK ? B_OK : token;
238 }
239 
240 
241 // FBC
242 void BMessageRunner::_ReservedMessageRunner1() {}
243 void BMessageRunner::_ReservedMessageRunner2() {}
244 void BMessageRunner::_ReservedMessageRunner3() {}
245 void BMessageRunner::_ReservedMessageRunner4() {}
246 void BMessageRunner::_ReservedMessageRunner5() {}
247 void BMessageRunner::_ReservedMessageRunner6() {}
248 
249 // copy constructor
250 /*!	\brief Privatized copy constructor to prevent usage.
251 */
252 BMessageRunner::BMessageRunner(const BMessageRunner &)
253 	: fToken(-1)
254 {
255 }
256 
257 // =
258 /*!	\brief Privatized assignment operator to prevent usage.
259 */
260 BMessageRunner &
261 BMessageRunner::operator=(const BMessageRunner &)
262 {
263 	return *this;
264 }
265 
266 
267 /*!	\brief Initializes the BMessageRunner.
268 
269 	The success of the initialization can (and should) be asked for via
270 	InitCheck().
271 
272 	\note As soon as the last message has been sent, the message runner
273 		  becomes unusable. InitCheck() will still return \c B_OK, but
274 		  SetInterval(), SetCount() and GetInfo() will fail.
275 
276 	\param target Target of the message(s).
277 	\param message The message to be sent to the target.
278 	\param interval Period of time before the first message is sent and
279 		   between messages (if more than one shall be sent) in microseconds.
280 	\param count Specifies how many times the message shall be sent.
281 		   A value less than \c 0 for an unlimited number of repetitions.
282 	\param replyTo Target replies to the delivered message(s) shall be sent to.
283 */
284 void
285 BMessageRunner::_InitData(BMessenger target, const BMessage *message,
286 	bigtime_t interval, int32 count, BMessenger replyTo)
287 {
288 	fToken = _RegisterRunner(target, message, interval, count, false, replyTo);
289 }
290 
291 
292 /*!	\brief Registers the BMessageRunner in the registrar.
293 
294 	\param target Target of the message(s).
295 	\param message The message to be sent to the target.
296 	\param interval Period of time before the first message is sent and
297 		   between messages (if more than one shall be sent) in microseconds.
298 	\param count Specifies how many times the message shall be sent.
299 		   A value less than \c 0 for an unlimited number of repetitions.
300 	\param replyTo Target replies to the delivered message(s) shall be sent to.
301 
302 	\return The token the message runner is registered with, or the error code
303 		while trying to register it.
304 */
305 /*static*/ int32
306 BMessageRunner::_RegisterRunner(BMessenger target, const BMessage *message,
307 	bigtime_t interval, int32 count, bool detach, BMessenger replyTo)
308 {
309 	status_t error = B_OK;
310 	if (message == NULL || count == 0 || (count < 0 && detach))
311 		error = B_BAD_VALUE;
312 
313 	// compose the request message
314 	BMessage request(B_REG_REGISTER_MESSAGE_RUNNER);
315 	if (error == B_OK)
316 		error = request.AddInt32("team", BPrivate::current_team());
317 	if (error == B_OK)
318 		error = request.AddMessenger("target", target);
319 	if (error == B_OK)
320 		error = request.AddMessage("message", message);
321 	if (error == B_OK)
322 		error = request.AddInt64("interval", interval);
323 	if (error == B_OK)
324 		error = request.AddInt32("count", count);
325 	if (error == B_OK)
326 		error = request.AddMessenger("reply_target", replyTo);
327 
328 	// send the request
329 	BMessage reply;
330 	if (error == B_OK)
331 		error = BRoster::Private().SendTo(&request, &reply, false);
332 
333 	int32 token;
334 
335 	// evaluate the reply
336 	if (error == B_OK) {
337 		if (reply.what == B_REG_SUCCESS) {
338 			if (reply.FindInt32("token", &token) != B_OK)
339 				error = B_ERROR;
340 		} else
341 			reply.FindInt32("error", &error);
342 	}
343 
344 	if (error == B_OK)
345 		return token;
346 
347 	return error;
348 }
349 
350 
351 /*!	\brief Sets the message runner's interval and count parameters.
352 
353 	The parameters \a resetInterval and \a resetCount specify whether
354 	the interval or the count parameter respectively shall be reset.
355 
356 	At least one parameter must be set, otherwise the methods returns
357 	\c B_BAD_VALUE.
358 
359 	\param resetInterval \c true, if the interval shall be reset, \c false
360 		   otherwise -- then \a interval is ignored.
361 	\param interval The new interval in microseconds.
362 	\param resetCount \c true, if the count shall be reset, \c false
363 		   otherwise -- then \a count is ignored.
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 	\return
367 	- \c B_OK: Everything went fine.
368 	- \c B_BAD_VALUE: The message runner is not longer valid. All the
369 	  messages that had to be sent have already been sent. Or both
370 	  \a resetInterval and \a resetCount are \c false.
371 */
372 status_t
373 BMessageRunner::_SetParams(bool resetInterval, bigtime_t interval,
374 	bool resetCount, int32 count)
375 {
376 	if ((!resetInterval && !resetCount) || fToken < 0)
377 		return B_BAD_VALUE;
378 
379 	// compose the request message
380 	BMessage request(B_REG_SET_MESSAGE_RUNNER_PARAMS);
381 	status_t error = request.AddInt32("token", fToken);
382 	if (error == B_OK && resetInterval)
383 		error = request.AddInt64("interval", interval);
384 	if (error == B_OK && resetCount)
385 		error = request.AddInt32("count", count);
386 
387 	// send the request
388 	BMessage reply;
389 	if (error == B_OK)
390 		error = BRoster::Private().SendTo(&request, &reply, false);
391 
392 	// evaluate the reply
393 	if (error == B_OK) {
394 		if (reply.what != B_REG_SUCCESS)
395 			reply.FindInt32("error", &error);
396 	}
397 	return error;
398 }
399 
400