Fix more warnings
[lash.git] / dbus / method.c
blobfe8255ec75f3ceb3d2d8611a8d289d0620cdf02f
1 /*
2 * LASH
4 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
5 * Copyright (C) 2008 Nedko Arnaudov
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "common/safety.h"
23 #include "common/debug.h"
25 #include "dbus/method.h"
26 #include "dbus/service.h"
29 * Construct a void method return.
31 * The operation can only fail due to lack of memory, in which case
32 * there's no sense in trying to construct an error return. Instead,
33 * call->reply will be set to NULL and handled in send_method_return().
35 void
36 method_return_new_void(method_call_t *call)
38 if (!(call->reply = dbus_message_new_method_return(call->message))) {
39 lash_error("Ran out of memory trying to construct method return");
44 * Construct a method return which holds a single argument or, if
45 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
46 * (a void message).
48 * The operation can only fail due to lack of memory, in which case
49 * there's no sense in trying to construct an error return. Instead,
50 * call->reply will be set to NULL and handled in send_method_return().
52 void
53 method_return_new_single(method_call_t *call,
54 int type,
55 const void *arg)
57 if (!call || !arg) {
58 lash_error("Invalid arguments");
59 return;
62 call->reply = dbus_message_new_method_return(call->message);
64 if (!call->reply)
65 goto fail_no_mem;
67 /* Void method return requested by caller. */
68 // TODO: do we really need this?
69 if (type == DBUS_TYPE_INVALID)
70 return;
72 /* Prevent crash on NULL input string. */
73 if (type == DBUS_TYPE_STRING && !(*((const char **) arg)))
74 *((const char **) arg) = "";
76 DBusMessageIter iter;
78 dbus_message_iter_init_append(call->reply, &iter);
80 if (dbus_message_iter_append_basic(&iter, type, arg))
81 return;
83 dbus_message_unref(call->reply);
84 call->reply = NULL;
86 fail_no_mem:
87 lash_error("Ran out of memory trying to construct method return");
90 void
91 method_return_new_valist(method_call_t *call,
92 int type,
93 ...)
95 if (!call) {
96 lash_error("Call pointer is NULL");
97 return;
100 if (type == DBUS_TYPE_INVALID) {
101 lash_error("No argument(s) supplied");
102 return;
105 va_list argp;
107 call->reply = dbus_message_new_method_return(call->message);
108 if (!call->reply)
109 goto fail_no_mem;
111 va_start(argp, type);
113 if (dbus_message_append_args_valist(call->reply, type, argp)) {
114 va_end(argp);
115 return;
118 va_end(argp);
120 dbus_message_unref(call->reply);
121 call->reply = NULL;
123 fail_no_mem:
124 lash_error("Ran out of memory trying to construct method return");
128 * Send a method call.
130 bool
131 method_send(method_msg_t *call,
132 bool will_block)
134 if (!call->message) {
135 lash_error("Cannot send method call: Message is NULL");
136 return false;
139 DBusPendingCall *pending = NULL;
140 bool retval;
142 if (!dbus_connection_send_with_reply(call->service->connection,
143 call->message, &pending, -1)) {
144 lash_error("Ran out of memory trying to queue "
145 "method call");
146 retval = false;
147 /* Never wait for a reply if sending failed */
148 will_block = false;
149 } else {
150 if (pending)
151 dbus_pending_call_set_notify(pending,
152 call->return_handler,
153 call->context, NULL);
154 dbus_connection_flush(call->service->connection);
155 retval = true;
158 dbus_message_unref(call->message);
159 call->message = NULL;
161 if (will_block && pending) {
162 lash_debug("Blocking until a return arrives");
163 dbus_pending_call_block(pending);
166 return retval;
170 * Send a method return.
172 * If call->reply is NULL, i.e. a previous attempt to construct
173 * a return has failed, attempt to send a void return.
175 void
176 method_return_send(method_call_t *call)
178 if (call->reply) {
179 retry_send:
180 if (!dbus_connection_send(call->connection, call->reply, NULL))
181 lash_error("Ran out of memory trying to queue "
182 "method return");
183 else
184 dbus_connection_flush(call->connection);
186 dbus_message_unref(call->reply);
187 call->reply = NULL;
188 } else {
189 lash_debug("Message was NULL, trying to construct a void return");
191 if ((call->reply = dbus_message_new_method_return(call->message))) {
192 lash_debug("Constructed a void return, trying to queue it");
193 goto retry_send;
194 } else {
195 lash_error("Failed to construct method return!");
200 bool
201 method_return_verify(DBusMessage *msg,
202 const char **str)
204 if (!msg || dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR)
205 return true;
207 DBusError err;
208 const char *ptr;
210 dbus_error_init(&err);
212 if (!dbus_message_get_args(msg, &err,
213 DBUS_TYPE_STRING, &ptr,
214 DBUS_TYPE_INVALID)) {
215 lash_error("Cannot read description from D-Bus error message: %s ",
216 err.message);
217 dbus_error_free(&err);
218 ptr = NULL;
221 if (str)
222 *str = ptr;
224 return false;
228 * Append a variant type to a D-Bus message.
229 * Return false if something fails, true otherwise.
231 bool
232 method_iter_append_variant(DBusMessageIter *iter,
233 int type,
234 const void *arg)
236 DBusMessageIter sub_iter;
237 char s[2];
239 s[0] = (char) type;
240 s[1] = '\0';
242 /* Open a variant container. */
243 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
244 (const char *) s, &sub_iter))
245 return false;
247 /* Append the supplied value. */
248 if (!dbus_message_iter_append_basic(&sub_iter, type, arg)) {
249 dbus_message_iter_close_container(iter, &sub_iter);
250 return false;
253 /* Close the container. */
254 if (!dbus_message_iter_close_container(iter, &sub_iter))
255 return false;
257 return true;
260 static __inline__ bool
261 method_iter_append_variant_raw(DBusMessageIter *iter,
262 const void *buf,
263 int len)
265 DBusMessageIter variant_iter, array_iter;
267 /* Open a variant container. */
268 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
269 "ay", &variant_iter))
270 return false;
272 /* Open an array container. */
273 if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
274 "y", &array_iter))
275 goto fail;
277 /* Append the supplied data. */
278 if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, buf, len)) {
279 dbus_message_iter_close_container(&variant_iter, &array_iter);
280 goto fail;
283 /* Close the containers. */
284 if (!dbus_message_iter_close_container(&variant_iter, &array_iter))
285 goto fail;
286 else if (!dbus_message_iter_close_container(iter, &variant_iter))
287 return false;
289 return true;
291 fail:
292 dbus_message_iter_close_container(iter, &variant_iter);
293 return false;
296 bool
297 method_iter_append_dict_entry(DBusMessageIter *iter,
298 int type,
299 const char *key,
300 const void *value,
301 int length)
303 DBusMessageIter dict_iter;
305 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
306 NULL, &dict_iter))
307 return false;
309 if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &key))
310 goto fail;
312 if (type == '-') {
313 if (!method_iter_append_variant_raw(&dict_iter, value, length))
314 goto fail;
315 } else if (!method_iter_append_variant(&dict_iter, type, value))
316 goto fail;
318 if (!dbus_message_iter_close_container(iter, &dict_iter))
319 return false;
321 return true;
323 fail:
324 dbus_message_iter_close_container(iter, &dict_iter);
325 return false;
328 void
329 method_default_handler(DBusPendingCall *pending,
330 void *data)
332 DBusMessage *msg = dbus_pending_call_steal_reply(pending);
334 if (msg) {
335 const char *err_str;
337 if (!method_return_verify(msg, &err_str))
338 lash_error("%s", err_str);
340 dbus_message_unref(msg);
341 } else
342 lash_error("Cannot get method return from pending call");
344 dbus_pending_call_unref(pending);
347 bool
348 method_call_init(method_msg_t *call,
349 service_t *service,
350 void *return_context,
351 DBusPendingCallNotifyFunction return_handler,
352 const char *destination,
353 const char *path,
354 const char *interface,
355 const char *method)
357 if (!call || !service || !service->connection
358 || !destination || !path || !method) {
359 lash_error("Invalid arguments");
360 return false;
363 if (!interface)
364 interface = "";
366 call->message = dbus_message_new_method_call(destination, path,
367 interface, method);
368 if (!call->message) {
369 lash_error("Ran out of memory trying to create "
370 "new method call");
371 return false;
374 call->service = service;
375 call->context = return_context;
376 call->return_handler = return_handler;
378 if (!return_handler)
379 dbus_message_set_no_reply(call->message, true);
381 return true;
384 bool
385 method_call_new_void(service_t *service,
386 void *return_context,
387 DBusPendingCallNotifyFunction return_handler,
388 bool will_block,
389 const char *destination,
390 const char *path,
391 const char *interface,
392 const char *method)
394 method_msg_t call;
396 if (method_call_init(&call, service, return_context, return_handler,
397 destination, path, interface, method))
398 return method_send(&call, will_block);
400 return false;
403 bool
404 method_call_new_single(service_t *service,
405 void *return_context,
406 DBusPendingCallNotifyFunction return_handler,
407 bool will_block,
408 const char *destination,
409 const char *path,
410 const char *interface,
411 const char *method,
412 int type,
413 const void *arg)
415 if (type == DBUS_TYPE_INVALID || !arg) {
416 lash_error("No argument supplied");
417 return false;
420 method_msg_t call;
421 DBusMessageIter iter;
423 if (!method_call_init(&call, service, return_context, return_handler,
424 destination, path, interface, method))
425 return false;
427 dbus_message_iter_init_append(call.message, &iter);
429 if (dbus_message_iter_append_basic(&iter, type, arg)) {
430 return method_send(&call, will_block);
433 lash_error("Ran out of memory trying to append method call argument");
435 dbus_message_unref(call.message);
436 call.message = NULL;
438 return false;
441 bool
442 method_call_new_valist(service_t *service,
443 void *return_context,
444 DBusPendingCallNotifyFunction return_handler,
445 bool will_block,
446 const char *destination,
447 const char *path,
448 const char *interface,
449 const char *method,
450 int type,
451 ...)
453 if (type == DBUS_TYPE_INVALID) {
454 lash_error("No argument(s) supplied");
455 return false;
458 method_msg_t call;
459 va_list argp;
461 if (!method_call_init(&call, service, return_context, return_handler,
462 destination, path, interface, method))
463 return false;
465 va_start(argp, type);
467 if (dbus_message_append_args_valist(call.message, type, argp)) {
468 va_end(argp);
469 return method_send(&call, will_block);
472 va_end(argp);
474 lash_error("Ran out of memory trying to append "
475 "method call argument(s)");
477 dbus_message_unref(call.message);
478 call.message = NULL;
480 return false;
483 bool
484 method_iter_get_args(DBusMessageIter *iter,
485 ...)
487 if (!iter) {
488 lash_error("Iterator pointer is NULL");
489 return false;
492 va_list argp;
493 int expected_type, type, n = 0;
494 void *ptr;
496 va_start(argp, iter);
498 while ((expected_type = va_arg(argp, int)) != DBUS_TYPE_INVALID) {
499 ptr = va_arg(argp, void *);
501 if ((type = dbus_message_iter_get_arg_type(iter))
502 == DBUS_TYPE_INVALID) {
503 lash_error("Insufficient arguments");
504 va_end(argp);
505 return false;
508 if (type != expected_type) {
509 lash_error("Invalid type for argument %i", n);
510 va_end(argp);
511 return false;
514 if (ptr)
515 dbus_message_iter_get_basic(iter, ptr);
517 dbus_message_iter_next(iter);
519 ++n;
522 va_end(argp);
524 return true;
527 bool
528 method_iter_get_dict_entry(DBusMessageIter *iter,
529 const char **key_ptr,
530 void *value_ptr,
531 int *type_ptr,
532 int *size_ptr)
534 if (!iter || !key_ptr || !value_ptr || !type_ptr) {
535 lash_error("Invalid arguments");
536 return false;
539 DBusMessageIter dict_iter, variant_iter;
541 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
542 lash_error("Iterator does not point to a dict entry container");
543 return false;
546 dbus_message_iter_recurse(iter, &dict_iter);
548 if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_STRING) {
549 lash_error("Cannot find key in dict entry container");
550 return false;
553 dbus_message_iter_get_basic(&dict_iter, key_ptr);
555 if (!dbus_message_iter_next(&dict_iter)
556 || dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_VARIANT) {
557 lash_error("Cannot find variant container in dict entry");
558 return false;
561 dbus_message_iter_recurse(&dict_iter, &variant_iter);
563 *type_ptr = dbus_message_iter_get_arg_type(&variant_iter);
564 if (*type_ptr == DBUS_TYPE_INVALID) {
565 lash_error("Cannot find value in variant container");
566 return false;
569 if (*type_ptr == DBUS_TYPE_ARRAY) {
570 DBusMessageIter array_iter;
571 int n;
573 if (dbus_message_iter_get_element_type(&variant_iter)
574 != DBUS_TYPE_BYTE) {
575 lash_error("Dict entry value is a non-byte array");
576 return false;
578 *type_ptr = '-';
580 dbus_message_iter_recurse(&variant_iter, &array_iter);
581 dbus_message_iter_get_fixed_array(&array_iter, value_ptr, &n);
583 if (size_ptr)
584 *size_ptr = n;
585 } else
586 dbus_message_iter_get_basic(&variant_iter, value_ptr);
588 return true;
591 /* EOF */