Really commit fixes; make unit tests pass
[platform/upstream/at-spi2-core.git] / dbind / dbind.c
1
2
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <glib.h>
6
7 #include "config.h"
8 #include "dbind/dbind.h"
9
10 static int dbind_timeout = -1;
11
12 /*
13  * FIXME: compare types - to ensure they match &
14  *        do dynamic padding of structures etc.
15  */
16
17 /*---------------------------------------------------------------------------*/
18
19 typedef struct _SpiReentrantCallClosure 
20 {
21   GMainLoop   *loop;
22   DBusMessage *reply;
23 } SpiReentrantCallClosure;
24
25 static void
26 set_reply (DBusPendingCall * pending, void *user_data)
27 {
28   SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; 
29
30   closure->reply = dbus_pending_call_steal_reply (pending);
31   g_main_loop_quit (closure->loop);
32 }
33
34 DBusMessage *
35 dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error)
36 {
37   DBusPendingCall *pending;
38   SpiReentrantCallClosure closure;
39
40   if (strcmp (dbus_message_get_destination (message),
41               dbus_bus_get_unique_name (bus)) != 0)
42     return dbus_connection_send_with_reply_and_block (bus, message, dbind_timeout, error);
43
44   if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout))
45       return NULL;
46   dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL);
47   closure.loop = g_main_loop_new (NULL, FALSE);
48   dbus_connection_setup_with_g_main(bus, NULL);
49
50   if (1)
51     {
52       g_main_loop_run  (closure.loop);
53     }
54   else
55     {
56       closure.reply = NULL;
57       while (!closure.reply)
58         {
59           if (!dbus_connection_read_write_dispatch (bus, dbind_timeout))
60             return NULL;
61         }
62     }
63   
64   g_main_loop_unref (closure.loop);
65   return closure.reply;
66 }
67
68 dbus_bool_t
69 dbind_method_call_reentrant_va (DBusConnection *cnx,
70                                 const char     *bus_name,
71                                 const char     *path,
72                                 const char     *interface,
73                                 const char     *method,
74                                 DBusError      *opt_error,
75                                 const char     *arg_types,
76                                 va_list         args)
77 {
78     dbus_bool_t success = FALSE;
79     DBusMessage *msg = NULL, *reply = NULL;
80     DBusMessageIter iter;
81     DBusError *err, real_err;
82     const char *p;
83   va_list args_demarshal;
84
85   va_copy (args_demarshal, args);
86     if (opt_error)
87         err = opt_error;
88     else {
89         dbus_error_init (&real_err);
90         err = &real_err;
91     }
92
93     msg = dbus_message_new_method_call (bus_name, path, interface, method);
94     if (!msg)
95         goto out;
96
97     p = arg_types;
98     dbus_message_iter_init_append (msg, &iter);
99     dbind_any_marshal_va (&iter, &p, args);
100
101     reply = dbind_send_and_allow_reentry (cnx, msg, err);
102     if (!reply)
103         goto out;
104
105     if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
106     {
107       const char *name = dbus_message_get_error_name (reply);
108       dbus_set_error (err, name, g_strdup (""));
109       goto out;
110     }
111     /* demarshal */
112     if (p[0] == '=' && p[1] == '>')
113     {
114         DBusMessageIter iter;
115         dbus_message_iter_init (reply, &iter);
116         p = arg_types;
117         dbind_any_demarshal_va (&iter, &p, args_demarshal);
118     }
119
120     success = TRUE;
121 out:
122     if (msg)
123         dbus_message_unref (msg);
124
125     if (reply)
126         dbus_message_unref (reply);
127
128     if (err == &real_err)
129         dbus_error_free (err);
130
131     va_end (args_demarshal);
132     return success;
133 }
134
135 /**
136  * dbind_method_call_reentrant:
137  *
138  * @cnx:       A D-Bus Connection used to make the method call.
139  * @bus_name:  The D-Bus bus name of the program where the method call should
140  *             be made.
141  * @path:      The D-Bus object path that should handle the method.
142  * @interface: The D-Bus interface used to scope the method name.
143  * @method:    Method to be invoked.
144  * @opt_error: D-Bus error.
145  * @arg_types: Variable length arguments interleaving D-Bus argument types
146  *             and pointers to argument data.
147  *
148  * Makes a D-Bus method call using the supplied location data, method name and
149  * argument data.This function is re-entrant. It continuously reads from the D-Bus
150  * bus and dispatches messages until a reply has been recieved.
151  **/
152 dbus_bool_t
153 dbind_method_call_reentrant (DBusConnection *cnx,
154                              const char     *bus_name,
155                              const char     *path,
156                              const char     *interface,
157                              const char     *method,
158                              DBusError      *opt_error,
159                              const char     *arg_types,
160                              ...)
161 {
162     dbus_bool_t success = FALSE;
163     va_list args;
164
165     va_start (args, arg_types);
166     success = dbind_method_call_reentrant_va (cnx,
167                                               bus_name,
168                                               path,
169                                               interface,
170                                               method,
171                                               opt_error,
172                                               arg_types,
173                                               args);
174     va_end (args);
175
176     return success;
177 }
178
179 /*---------------------------------------------------------------------------*/
180
181 dbus_bool_t
182 dbind_emit_signal_va (DBusConnection *cnx,
183                       const char     *path,
184                       const char     *interface,
185                       const char     *signal,
186                       DBusError      *opt_error,
187                       const char     *arg_types,
188                       va_list         args)
189 {
190     dbus_bool_t success = FALSE;
191     DBusMessage *msg = NULL;
192     DBusMessageIter iter;
193     DBusError *err, real_err;
194     const char *p;
195
196     if (opt_error)
197         err = opt_error;
198     else {
199         dbus_error_init (&real_err);
200         err = &real_err;
201     }
202
203     msg = dbus_message_new_signal (path, interface, signal);
204     if (!msg)
205         goto out;
206
207     p = arg_types;
208     dbus_message_iter_init_append (msg, &iter);
209     dbind_any_marshal_va (&iter, &p, args);
210
211     if (!dbus_connection_send (cnx, msg, NULL))
212        goto out;
213
214     success = TRUE;
215 out:
216
217     if (msg)
218         dbus_message_unref (msg);
219
220     if (err == &real_err)
221         dbus_error_free (err);
222
223     return success;
224 }
225
226 /**
227  * dbind_emit_signal:
228  *
229  * @cnx:       A D-Bus Connection used to make the method call.
230  * @path:      The D-Bus object path that this signal is emitted from.
231  * @interface: The D-Bus interface used to scope the method name.
232  * @signal:    Name of signal to emit.
233  * @opt_error: D-Bus error.
234  * @arg_types: Variable length arguments interleaving D-Bus argument types
235  *             and pointers to argument data.
236  *
237  * Emits a D-Bus signal  using the supplied signal name and argument data.
238  **/
239 dbus_bool_t
240 dbind_emit_signal (DBusConnection *cnx,
241                    const char     *path,
242                    const char     *interface,
243                    const char     *signal,
244                    DBusError      *opt_error,
245                    const char     *arg_types,
246                    ...)
247 {
248     dbus_bool_t success = FALSE;
249     va_list args;
250
251     va_start (args, arg_types);
252     success = dbind_emit_signal_va (cnx, path, interface, signal, opt_error, arg_types, args);
253     va_end (args);
254
255     return success;
256 }
257 void
258 dbind_set_timeout (int timeout)
259 {
260   dbind_timeout = timeout;
261 }
262
263
264 /*END------------------------------------------------------------------------*/