Merge branch 'mgorse' of git+ssh://git.codethink.co.uk/git/atspi-dbus into rework
[platform/core/uifw/at-spi2-atk.git] / droute / droute.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2008 Novell, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "droute.h"
27
28 static DRouteInterface *
29 find_iface (DRouteData * data, const char *name)
30 {
31   GSList *l;
32
33   for (l = data->interfaces; l; l = g_slist_next (l))
34     {
35       DRouteInterface *iface = (DRouteInterface *) l->data;
36       if (iface && iface->name && !strcmp (iface->name, name))
37         return iface;
38     }
39   return NULL;
40 }
41
42 static DBusHandlerResult
43 prop_get_all (DBusConnection * bus, DBusMessage * message, DRouteData * data)
44 {
45   DRouteInterface *iface_def;
46   DRouteProperty *prop;
47   DBusError error;
48   const char *iface;
49   const char *path = dbus_message_get_path (message);
50   DBusMessage *reply;
51   DBusMessageIter iter, iter_dict, iter_dict_entry;
52
53   dbus_error_init (&error);
54   if (!dbus_message_get_args
55       (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID))
56     {
57       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
58     }
59   reply = dbus_message_new_method_return (message);
60   /* tbd: replace tbd with todo? */
61   if (!reply)
62     goto oom;
63   dbus_message_iter_init_append (reply, &iter);
64   if (!dbus_message_iter_open_container
65       (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict))
66     goto oom;
67   iface_def = find_iface (data, iface);
68   if (!iface_def)
69     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
70   if (iface_def->properties)
71     for (prop = iface_def->properties; prop->name; prop++)
72       {
73         if (!prop->get)
74           continue;
75         if (!dbus_message_iter_open_container
76             (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry))
77           goto oom;
78         dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING,
79                                         &prop->name);
80         (*prop->get) (path, &iter_dict_entry, data->user_data);
81         if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
82           goto oom;
83       }
84   if (!dbus_message_iter_close_container (&iter, &iter_dict))
85     goto oom;
86   dbus_connection_send (bus, reply, NULL);
87   dbus_message_unref (reply);
88   return DBUS_HANDLER_RESULT_HANDLED;
89 oom:
90   /* tbd: return a standard out-of-memory error */
91   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
92 }
93
94 static DBusHandlerResult
95 prop (DBusConnection * bus, DBusMessage * message, DRouteData * data)
96 {
97   const char *mode = dbus_message_get_member (message);
98   const char *iface, *member;
99   const char *path = dbus_message_get_path (message);
100   int set;
101   DBusMessage *reply;
102   DBusMessageIter iter;
103   DRouteInterface *iface_def;
104   DRouteProperty *prop = NULL;
105
106   if (!strcmp (mode, "Set"))
107     set = 1;
108   else if (!strcmp (mode, "Get"))
109     set = 0;
110   else
111     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
112   reply = dbus_message_new_method_return (message);
113   dbus_message_iter_init (message, &iter);
114   dbus_message_iter_get_basic (&iter, &iface);
115   dbus_message_iter_next (&iter);
116   dbus_message_iter_get_basic (&iter, &member);
117   if (!set)
118     dbus_message_iter_init_append (reply, &iter);
119   iface_def = find_iface (data, iface);
120   if (!iface_def)
121     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
122   if (iface_def->properties)
123     for (prop = iface_def->properties;
124          prop->name && strcmp (prop->name, member); prop++)
125       if (!prop || !prop->name)
126         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
127   if (set)
128     {
129       if (!prop->set)
130         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
131       (*prop->set) (path, &iter, data->user_data);
132     }
133   else
134     {
135       if (!prop->get)
136         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
137       (*prop->get) (path, &iter, data->user_data);
138     }
139   dbus_connection_send (bus, reply, NULL);
140   dbus_message_unref (reply);
141   return DBUS_HANDLER_RESULT_HANDLED;
142 }
143
144 DBusHandlerResult
145 droute_message (DBusConnection * bus, DBusMessage * message, void *user_data)
146 {
147   DRouteData *data = (DRouteData *) user_data;
148   DRouteInterface *iface_def;
149   DRouteMethod *method;
150   const char *iface = dbus_message_get_interface (message);
151   const char *member = dbus_message_get_member (message);
152   int type;
153   DBusError error;
154   DBusMessage *reply;
155
156   dbus_error_init (&error);
157   if (!member)
158     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
159   if (iface && !strcmp (iface, "org.freedesktop.DBus.Properties"))
160     {
161       if (!strcmp (member, "GetAll"))
162         return prop_get_all (bus, message, data);
163       return prop (bus, message, data);
164     }
165   if (iface)
166     {
167       iface_def = find_iface (data, iface);
168       if (!iface_def)
169         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
170       if (iface_def->methods)
171         for (method = iface_def->methods; method->func; method++)
172           {
173             if (!strcmp (method->name, member))
174               {
175                 reply =
176                   (*method->func) (bus, message,
177                                    (method->wants_droute_data ? data : data->
178                                     user_data));
179                 if (reply)
180                   {
181                     dbus_connection_send (bus, reply, NULL);
182                     dbus_message_unref (reply);
183                   }
184                 return DBUS_HANDLER_RESULT_HANDLED;
185               }
186           }
187     }
188   else
189     {
190       GSList *l;
191       if (type == DBUS_MESSAGE_TYPE_SIGNAL)
192         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
193       for (l = data->interfaces; l; l = g_slist_next (l))
194         {
195           iface_def = (DRouteInterface *) l->data;
196           if (iface_def->methods)
197             for (method = iface_def->methods; method->func; method++)
198               {
199                 if (!strcmp (method->name, member))
200                   {
201                     reply = (*method->func) (bus, message, data->user_data);
202                     if (reply)
203                       {
204                         dbus_connection_send (bus, reply, NULL);
205                         dbus_message_unref (reply);
206                       }
207                     return DBUS_HANDLER_RESULT_HANDLED;
208                   }
209               }
210         }
211     }
212   return DBUS_HANDLER_RESULT_HANDLED;
213 }
214
215 dbus_bool_t
216 droute_return_v_int32 (DBusMessageIter * iter, dbus_int32_t val)
217 {
218   DBusMessageIter sub;
219
220   if (!dbus_message_iter_open_container
221       (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub))
222     {
223       return FALSE;
224     }
225   dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &val);
226   dbus_message_iter_close_container (iter, &sub);
227   return TRUE;
228 }
229
230 dbus_bool_t
231 droute_return_v_double (DBusMessageIter * iter, double val)
232 {
233   DBusMessageIter sub;
234
235   if (!dbus_message_iter_open_container
236       (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub))
237     {
238       return FALSE;
239     }
240   dbus_message_iter_append_basic (&sub, DBUS_TYPE_DOUBLE, &val);
241   dbus_message_iter_close_container (iter, &sub);
242   return TRUE;
243 }
244
245 /* Return a string in a variant
246  * will return an empty string if passed a NULL value */
247 dbus_bool_t
248 droute_return_v_string (DBusMessageIter * iter, const char *val)
249 {
250   DBusMessageIter sub;
251
252   if (!val)
253     val = "";
254   if (!dbus_message_iter_open_container
255       (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub))
256     {
257       return FALSE;
258     }
259   dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &val);
260   dbus_message_iter_close_container (iter, &sub);
261   return TRUE;
262 }
263
264 dbus_int32_t
265 droute_get_v_int32 (DBusMessageIter * iter)
266 {
267   DBusMessageIter sub;
268   dbus_int32_t rv;
269
270   // TODO- ensure we have the correct type
271   dbus_message_iter_recurse (iter, &sub);
272   dbus_message_iter_get_basic (&sub, &rv);
273   return rv;
274 }
275
276 const char *
277 droute_get_v_string (DBusMessageIter * iter)
278 {
279   DBusMessageIter sub;
280   char *rv;
281
282   // TODO- ensure we have the correct type
283   dbus_message_iter_recurse (iter, &sub);
284   dbus_message_iter_get_basic (&sub, &rv);
285   return rv;
286 }
287
288 dbus_bool_t
289 droute_return_v_object (DBusMessageIter * iter, const char *path)
290 {
291   DBusMessageIter sub;
292
293   if (!dbus_message_iter_open_container
294       (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub))
295     {
296       return FALSE;
297     }
298   dbus_message_iter_append_basic (&sub, DBUS_TYPE_OBJECT_PATH, &path);
299   dbus_message_iter_close_container (iter, &sub);
300   return TRUE;
301 }
302
303 dbus_bool_t
304 droute_add_interface (DRouteData * data, const char *name,
305                       DRouteMethod * methods, DRouteProperty * properties,
306                       DRouteGetDatumFunction get_datum,
307                       DRouteFreeDatumFunction free_datum)
308 {
309   DRouteInterface *iface =
310     (DRouteInterface *) malloc (sizeof (DRouteInterface));
311   GSList *new_list;
312
313   if (!iface)
314     return FALSE;
315   iface->name = strdup (name);
316   if (!iface->name)
317     {
318       free (iface);
319       return FALSE;
320     }
321   iface->methods = methods;
322   iface->properties = properties;
323   iface->get_datum = get_datum;
324   iface->free_datum = free_datum;
325   new_list = g_slist_append (data->interfaces, iface);
326   if (!new_list)
327     {
328       free (iface->name);
329       free (iface);
330       return FALSE;
331     }
332   data->interfaces = new_list;
333   return TRUE;
334 }