202 lines
5.5 KiB
C
202 lines
5.5 KiB
C
/*
|
|
* LASH
|
|
*
|
|
* Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
|
|
* Copyright (C) 2008 Nedko Arnaudov
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dbus/dbus.h>
|
|
|
|
#include "../common/safety.h"
|
|
#include "../common/debug.h"
|
|
#include "introspection.h"
|
|
#include "signal.h"
|
|
#include "method.h"
|
|
|
|
#define write_buf(args...) buf_ptr += sprintf(buf_ptr, ## args)
|
|
|
|
DBusMessage *
|
|
introspection_new(object_path_t *path)
|
|
{
|
|
if (!path) {
|
|
lash_debug("Invalid arguments");
|
|
return NULL;
|
|
}
|
|
|
|
lash_debug("Creating introspection message");
|
|
|
|
char *xml_data, *buf_ptr;
|
|
const interface_t **iface_pptr;
|
|
const method_t *method_ptr;
|
|
const method_arg_t *method_arg_ptr;
|
|
const signal_t *signal_ptr;
|
|
const signal_arg_t *signal_arg_ptr;
|
|
DBusMessage *msg;
|
|
DBusMessageIter iter;
|
|
|
|
/*
|
|
* Create introspection XML data.
|
|
*/
|
|
|
|
xml_data = lash_malloc(1, 16384);
|
|
buf_ptr = xml_data;
|
|
|
|
write_buf("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
|
|
" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
|
"<node name=\"%s\">\n", path->name);
|
|
|
|
/* Add the object path's interfaces. */
|
|
for (iface_pptr = (const interface_t **) path->interfaces;
|
|
iface_pptr && *iface_pptr;
|
|
++iface_pptr) {
|
|
write_buf(" <interface name=\"%s\">\n",
|
|
(*iface_pptr)->name);
|
|
|
|
/* Add the interface's methods. */
|
|
for (method_ptr = (const method_t *) (*iface_pptr)->methods;
|
|
method_ptr && method_ptr->name;
|
|
++method_ptr) {
|
|
write_buf(" <method name=\"%s\">\n",
|
|
method_ptr->name);
|
|
|
|
/* Add the method's arguments. */
|
|
for (method_arg_ptr = (const method_arg_t *) method_ptr->args;
|
|
method_arg_ptr && method_arg_ptr->name;
|
|
++method_arg_ptr) {
|
|
write_buf(" <arg name=\"%s\" type=\"%s\" direction=\"%s\" />\n",
|
|
method_arg_ptr->name,
|
|
method_arg_ptr->type,
|
|
method_arg_ptr->direction == DIRECTION_IN ? "in" : "out");
|
|
}
|
|
write_buf(" </method>\n");
|
|
}
|
|
|
|
/* Add the interface's signals. */
|
|
for (signal_ptr = (const signal_t *) (*iface_pptr)->signals;
|
|
signal_ptr && signal_ptr->name;
|
|
++signal_ptr) {
|
|
write_buf(" <signal name=\"%s\">\n",
|
|
signal_ptr->name);
|
|
|
|
/* Add the signal's arguments. */
|
|
for (signal_arg_ptr = (const signal_arg_t *) signal_ptr->args;
|
|
signal_arg_ptr && signal_arg_ptr->name;
|
|
++signal_arg_ptr) {
|
|
write_buf(" <arg name=\"%s\" type=\"%s\" />\n",
|
|
signal_arg_ptr->name,
|
|
signal_arg_ptr->type);
|
|
}
|
|
write_buf(" </signal>\n");
|
|
}
|
|
write_buf(" </interface>\n");
|
|
}
|
|
write_buf("</node>");
|
|
|
|
/*
|
|
* Create a D-Bus message from the XML data.
|
|
*/
|
|
|
|
if ((msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN))) {
|
|
dbus_message_iter_init_append(msg, &iter);
|
|
if (dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
|
|
(const void *) &xml_data)) {
|
|
dbus_message_set_no_reply(msg, TRUE);
|
|
} else {
|
|
dbus_message_unref(msg);
|
|
msg = NULL;
|
|
lash_error("Failed to append data to introspection message");
|
|
}
|
|
} else {
|
|
lash_error("Failed to create introspection message");
|
|
}
|
|
|
|
free(xml_data);
|
|
xml_data = buf_ptr = NULL;
|
|
|
|
return msg;
|
|
}
|
|
|
|
#undef write_buf
|
|
|
|
void
|
|
introspection_destroy(object_path_t *path)
|
|
{
|
|
lash_debug("Destroying introspection message");
|
|
|
|
if (path && path->introspection) {
|
|
dbus_message_unref(path->introspection);
|
|
path->introspection = NULL;
|
|
}
|
|
#ifdef LASH_DEBUG
|
|
else
|
|
lash_debug("Nothing to destroy");
|
|
#endif
|
|
}
|
|
|
|
static bool
|
|
introspection_handler(const interface_t *interface,
|
|
method_call_t *call)
|
|
{
|
|
if (strcmp(call->method_name, "Introspect") == 0) {
|
|
/* Try to construct the instrospection message */
|
|
if ((call->reply = dbus_message_copy(((object_path_t *) call->context)->introspection))
|
|
&& dbus_message_set_destination(call->reply, dbus_message_get_sender(call->message))
|
|
&& dbus_message_set_reply_serial(call->reply, dbus_message_get_serial(call->message))) {
|
|
return true;
|
|
}
|
|
|
|
/* Failed; clear the message data if it exists. */
|
|
if (call->reply) {
|
|
dbus_message_unref(call->reply);
|
|
call->reply = NULL;
|
|
}
|
|
|
|
lash_error("Ran out of memory trying to copy introspection message");
|
|
|
|
/* Even after an error we need to return true, because the
|
|
handler is only supposed to return false if a nonexistent
|
|
method is requested. */
|
|
return true;
|
|
}
|
|
|
|
/* The requested method wasn't "Introspect". */
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Interface description.
|
|
*/
|
|
|
|
METHOD_ARGS_BEGIN(Introspect)
|
|
METHOD_ARG_DESCRIBE("xml_data", "s", DIRECTION_OUT)
|
|
METHOD_ARGS_END
|
|
|
|
METHODS_BEGIN
|
|
METHOD_DESCRIBE(Introspect, NULL)
|
|
METHODS_END
|
|
|
|
INTERFACE_BEGIN(g_dbus_interface_dtor_introspectable, "org.freedesktop.DBus.Introspectable")
|
|
INTERFACE_HANDLER(introspection_handler)
|
|
INTERFACE_EXPOSE_METHODS
|
|
INTERFACE_END
|
|
|
|
/* EOF */
|