Dual license dbus helpers to match the libdbus licensing
[ladish.git] / dbus / method.c
blob03889d527235b3921fb5e7e4077c2776a2e722fd
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
8 **************************************************************************
9 * This file contains D-Bus methods helpers
10 **************************************************************************
12 * Licensed under the Academic Free License version 2.1
14 * LADI Session Handler is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * LADI Session Handler is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
26 * or write to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "../common.h"
31 #include "../common/safety.h"
32 #include "helpers.h"
33 #include "method.h"
36 * Construct a void method return.
38 * The operation can only fail due to lack of memory, in which case
39 * there's no sense in trying to construct an error return. Instead,
40 * call->reply will be set to NULL and handled in send_method_return().
42 void
43 method_return_new_void(method_call_t *call)
45 if (!(call->reply = dbus_message_new_method_return(call->message))) {
46 lash_error("Ran out of memory trying to construct method return");
51 * Construct a method return which holds a single argument or, if
52 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
53 * (a void message).
55 * The operation can only fail due to lack of memory, in which case
56 * there's no sense in trying to construct an error return. Instead,
57 * call->reply will be set to NULL and handled in send_method_return().
59 void
60 method_return_new_single(method_call_t *call,
61 int type,
62 const void *arg)
64 if (!call || !arg) {
65 lash_error("Invalid arguments");
66 return;
69 call->reply = dbus_message_new_method_return(call->message);
71 if (!call->reply)
72 goto fail_no_mem;
74 /* Void method return requested by caller. */
75 // TODO: do we really need this?
76 if (type == DBUS_TYPE_INVALID)
77 return;
79 /* Prevent crash on NULL input string. */
80 if (type == DBUS_TYPE_STRING && !(*((const char **) arg)))
81 *((const char **) arg) = "";
83 DBusMessageIter iter;
85 dbus_message_iter_init_append(call->reply, &iter);
87 if (dbus_message_iter_append_basic(&iter, type, arg))
88 return;
90 dbus_message_unref(call->reply);
91 call->reply = NULL;
93 fail_no_mem:
94 lash_error("Ran out of memory trying to construct method return");
97 void
98 method_return_new_valist(method_call_t *call,
99 int type,
100 ...)
102 if (!call) {
103 lash_error("Call pointer is NULL");
104 return;
107 if (type == DBUS_TYPE_INVALID) {
108 lash_error("No argument(s) supplied");
109 return;
112 va_list argp;
114 call->reply = dbus_message_new_method_return(call->message);
115 if (!call->reply)
116 goto fail_no_mem;
118 va_start(argp, type);
120 if (dbus_message_append_args_valist(call->reply, type, argp)) {
121 va_end(argp);
122 return;
125 va_end(argp);
127 dbus_message_unref(call->reply);
128 call->reply = NULL;
130 fail_no_mem:
131 lash_error("Ran out of memory trying to construct method return");
135 * Send a method return.
137 * If call->reply is NULL, i.e. a previous attempt to construct
138 * a return has failed, attempt to send a void return.
140 void
141 method_return_send(method_call_t *call)
143 if (call->reply) {
144 retry_send:
145 if (!dbus_connection_send(call->connection, call->reply, NULL))
146 lash_error("Ran out of memory trying to queue "
147 "method return");
148 else
149 dbus_connection_flush(call->connection);
151 dbus_message_unref(call->reply);
152 call->reply = NULL;
153 } else {
154 lash_debug("Message was NULL, trying to construct a void return");
156 if ((call->reply = dbus_message_new_method_return(call->message))) {
157 lash_debug("Constructed a void return, trying to queue it");
158 goto retry_send;
159 } else {
160 lash_error("Failed to construct method return!");
165 bool
166 method_return_verify(DBusMessage *msg,
167 const char **str)
169 if (!msg || dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR)
170 return true;
172 const char *ptr;
174 if (!dbus_message_get_args(msg, &g_dbus_error,
175 DBUS_TYPE_STRING, &ptr,
176 DBUS_TYPE_INVALID)) {
177 lash_error("Cannot read description from D-Bus error message: %s ",
178 g_dbus_error.message);
179 dbus_error_free(&g_dbus_error);
180 ptr = NULL;
183 if (str)
184 *str = ptr;
186 return false;
190 * Append a variant type to a D-Bus message.
191 * Return false if something fails, true otherwise.
193 bool
194 method_iter_append_variant(DBusMessageIter *iter,
195 int type,
196 const void *arg)
198 DBusMessageIter sub_iter;
199 char s[2];
201 s[0] = (char) type;
202 s[1] = '\0';
204 /* Open a variant container. */
205 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
206 (const char *) s, &sub_iter))
207 return false;
209 /* Append the supplied value. */
210 if (!dbus_message_iter_append_basic(&sub_iter, type, arg)) {
211 dbus_message_iter_close_container(iter, &sub_iter);
212 return false;
215 /* Close the container. */
216 if (!dbus_message_iter_close_container(iter, &sub_iter))
217 return false;
219 return true;
222 static __inline__ bool
223 method_iter_append_variant_raw(DBusMessageIter *iter,
224 const void *buf,
225 int len)
227 DBusMessageIter variant_iter, array_iter;
229 /* Open a variant container. */
230 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
231 "ay", &variant_iter))
232 return false;
234 /* Open an array container. */
235 if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
236 "y", &array_iter))
237 goto fail;
239 /* Append the supplied data. */
240 if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, buf, len)) {
241 dbus_message_iter_close_container(&variant_iter, &array_iter);
242 goto fail;
245 /* Close the containers. */
246 if (!dbus_message_iter_close_container(&variant_iter, &array_iter))
247 goto fail;
248 else if (!dbus_message_iter_close_container(iter, &variant_iter))
249 return false;
251 return true;
253 fail:
254 dbus_message_iter_close_container(iter, &variant_iter);
255 return false;
258 bool
259 method_iter_append_dict_entry(DBusMessageIter *iter,
260 int type,
261 const char *key,
262 const void *value,
263 int length)
265 DBusMessageIter dict_iter;
267 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
268 NULL, &dict_iter))
269 return false;
271 if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &key))
272 goto fail;
274 if (type == '-') {
275 if (!method_iter_append_variant_raw(&dict_iter, value, length))
276 goto fail;
277 } else if (!method_iter_append_variant(&dict_iter, type, value))
278 goto fail;
280 if (!dbus_message_iter_close_container(iter, &dict_iter))
281 return false;
283 return true;
285 fail:
286 dbus_message_iter_close_container(iter, &dict_iter);
287 return false;
290 bool
291 method_iter_get_dict_entry(DBusMessageIter *iter,
292 const char **key_ptr,
293 void *value_ptr,
294 int *type_ptr,
295 int *size_ptr)
297 if (!iter || !key_ptr || !value_ptr || !type_ptr) {
298 lash_error("Invalid arguments");
299 return false;
302 DBusMessageIter dict_iter, variant_iter;
304 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
305 lash_error("Iterator does not point to a dict entry container");
306 return false;
309 dbus_message_iter_recurse(iter, &dict_iter);
311 if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_STRING) {
312 lash_error("Cannot find key in dict entry container");
313 return false;
316 dbus_message_iter_get_basic(&dict_iter, key_ptr);
318 if (!dbus_message_iter_next(&dict_iter)
319 || dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_VARIANT) {
320 lash_error("Cannot find variant container in dict entry");
321 return false;
324 dbus_message_iter_recurse(&dict_iter, &variant_iter);
326 *type_ptr = dbus_message_iter_get_arg_type(&variant_iter);
327 if (*type_ptr == DBUS_TYPE_INVALID) {
328 lash_error("Cannot find value in variant container");
329 return false;
332 if (*type_ptr == DBUS_TYPE_ARRAY) {
333 DBusMessageIter array_iter;
334 int n;
336 if (dbus_message_iter_get_element_type(&variant_iter)
337 != DBUS_TYPE_BYTE) {
338 lash_error("Dict entry value is a non-byte array");
339 return false;
341 *type_ptr = '-';
343 dbus_message_iter_recurse(&variant_iter, &array_iter);
344 dbus_message_iter_get_fixed_array(&array_iter, value_ptr, &n);
346 if (size_ptr)
347 *size_ptr = n;
348 } else
349 dbus_message_iter_get_basic(&variant_iter, value_ptr);
351 return true;
354 /* EOF */