Quit when requested from the menu
[ladish.git] / dbus / introspection.c
blob379277415065c74cbc848f41d4f5c4ae93dde448
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 the D-Bus introspection interface handler
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <dbus/dbus.h>
33 #include "../common/safety.h"
34 #include "../common/debug.h"
35 #include "introspection.h"
36 #include "signal.h"
37 #include "method.h"
39 #define write_buf(args...) buf_ptr += sprintf(buf_ptr, ## args)
41 DBusMessage *
42 introspection_new(object_path_t *path)
44 if (!path) {
45 lash_debug("Invalid arguments");
46 return NULL;
49 lash_debug("Creating introspection message");
51 char *xml_data, *buf_ptr;
52 const interface_t **iface_pptr;
53 const method_t *method_ptr;
54 const method_arg_t *method_arg_ptr;
55 const signal_t *signal_ptr;
56 const signal_arg_t *signal_arg_ptr;
57 DBusMessage *msg;
58 DBusMessageIter iter;
61 * Create introspection XML data.
64 xml_data = lash_malloc(1, 16384);
65 buf_ptr = xml_data;
67 write_buf("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
68 " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
69 "<node name=\"%s\">\n", path->name);
71 /* Add the object path's interfaces. */
72 for (iface_pptr = (const interface_t **) path->interfaces;
73 iface_pptr && *iface_pptr;
74 ++iface_pptr) {
75 write_buf(" <interface name=\"%s\">\n",
76 (*iface_pptr)->name);
78 /* Add the interface's methods. */
79 for (method_ptr = (const method_t *) (*iface_pptr)->methods;
80 method_ptr && method_ptr->name;
81 ++method_ptr) {
82 write_buf(" <method name=\"%s\">\n",
83 method_ptr->name);
85 /* Add the method's arguments. */
86 for (method_arg_ptr = (const method_arg_t *) method_ptr->args;
87 method_arg_ptr && method_arg_ptr->name;
88 ++method_arg_ptr) {
89 write_buf(" <arg name=\"%s\" type=\"%s\" direction=\"%s\" />\n",
90 method_arg_ptr->name,
91 method_arg_ptr->type,
92 method_arg_ptr->direction_in ? "in" : "out");
94 write_buf(" </method>\n");
97 /* Add the interface's signals. */
98 for (signal_ptr = (const signal_t *) (*iface_pptr)->signals;
99 signal_ptr && signal_ptr->name;
100 ++signal_ptr) {
101 write_buf(" <signal name=\"%s\">\n",
102 signal_ptr->name);
104 /* Add the signal's arguments. */
105 for (signal_arg_ptr = (const signal_arg_t *) signal_ptr->args;
106 signal_arg_ptr && signal_arg_ptr->name;
107 ++signal_arg_ptr) {
108 write_buf(" <arg name=\"%s\" type=\"%s\" />\n",
109 signal_arg_ptr->name,
110 signal_arg_ptr->type);
112 write_buf(" </signal>\n");
114 write_buf(" </interface>\n");
116 write_buf("</node>");
119 * Create a D-Bus message from the XML data.
122 if ((msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN))) {
123 dbus_message_iter_init_append(msg, &iter);
124 if (dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
125 (const void *) &xml_data)) {
126 dbus_message_set_no_reply(msg, TRUE);
127 } else {
128 dbus_message_unref(msg);
129 msg = NULL;
130 lash_error("Failed to append data to introspection message");
132 } else {
133 lash_error("Failed to create introspection message");
136 free(xml_data);
137 xml_data = buf_ptr = NULL;
139 return msg;
142 #undef write_buf
144 void
145 introspection_destroy(object_path_t *path)
147 lash_debug("Destroying introspection message");
149 if (path && path->introspection) {
150 dbus_message_unref(path->introspection);
151 path->introspection = NULL;
153 #ifdef LASH_DEBUG
154 else
155 lash_debug("Nothing to destroy");
156 #endif
159 static bool
160 introspection_handler(const interface_t *interface,
161 method_call_t *call)
163 if (strcmp(call->method_name, "Introspect") == 0) {
164 /* Try to construct the instrospection message */
165 if ((call->reply = dbus_message_copy(((object_path_t *) call->context)->introspection))
166 && dbus_message_set_destination(call->reply, dbus_message_get_sender(call->message))
167 && dbus_message_set_reply_serial(call->reply, dbus_message_get_serial(call->message))) {
168 return true;
171 /* Failed; clear the message data if it exists. */
172 if (call->reply) {
173 dbus_message_unref(call->reply);
174 call->reply = NULL;
177 lash_error("Ran out of memory trying to copy introspection message");
179 /* Even after an error we need to return true, because the
180 handler is only supposed to return false if a nonexistent
181 method is requested. */
182 return true;
185 /* The requested method wasn't "Introspect". */
186 return false;
191 * Interface description.
194 METHOD_ARGS_BEGIN(Introspect, "Get introspection XML")
195 METHOD_ARG_DESCRIBE_OUT("xml_data", "s", "XML description of the object")
196 METHOD_ARGS_END
198 METHODS_BEGIN
199 METHOD_DESCRIBE(Introspect, NULL)
200 METHODS_END
202 INTERFACE_BEGIN(g_dbus_interface_dtor_introspectable, "org.freedesktop.DBus.Introspectable")
203 INTERFACE_HANDLER(introspection_handler)
204 INTERFACE_EXPOSE_METHODS
205 INTERFACE_END
207 /* EOF */