1bbf0b0f5628fea1b3484e82cbdb70c11742b4dc
[platform/core/uifw/at-spi2-atk.git] / dbind / dbind.c
1 #include "config.h"
2 #include <stdio.h>
3 #define DBUS_API_SUBJECT_TO_CHANGE
4 #include <dbind/dbind.h>
5 #include <dbind/dbind-any.h>
6 #include <glib.h>
7 #include <stdarg.h>
8
9 /*
10  * FIXME: compare types - to ensure they match &
11  *        do dynamic padding of structures etc.
12  */
13
14 struct _DBindContext {
15     DBusConnection *cnx;
16 };
17
18 DBindContext *
19 dbind_create_context (DBusBusType type, DBusError *opt_error)
20 {
21     DBindContext *ctx = NULL;
22     DBusConnection *cnx;
23     DBusError *err, real_err;
24     
25     if (opt_error)
26         err = opt_error;
27     else {
28         dbus_error_init (&real_err);
29         err = &real_err;
30     }
31    
32     cnx = dbus_bus_get (DBUS_BUS_SESSION, err);
33     if (!cnx)
34         goto out;
35
36     ctx = g_new0 (DBindContext, 1);
37     ctx->cnx = cnx;
38
39 out:
40     if (err == &real_err)
41         dbus_error_free (err);
42
43     return ctx;
44 }
45
46 void
47 dbind_context_free (DBindContext *ctx)
48 {
49     if (!ctx)
50         return;
51     dbus_connection_unref (ctx->cnx);
52     g_free (ctx);
53 }
54
55 dbus_bool_t
56 dbind_context_method_call (DBindContext *ctx,
57                            const char *bus_name,
58                            const char *path,
59                            const char *interface,
60                            const char *method,
61                            DBusError *opt_error,
62                            const char *arg_types,
63                            ...)
64 {
65     dbus_bool_t success;
66     va_list args;
67
68     va_start (args, arg_types);
69
70     success = dbind_connection_method_call_va
71         (ctx->cnx, bus_name, path, interface, method, opt_error, arg_types, args);
72
73     va_end (args);
74
75     return success;
76 }
77
78 dbus_bool_t
79 dbind_connection_method_call (DBusConnection *cnx,
80                               const char *bus_name,
81                               const char *path,
82                               const char *interface,
83                               const char *method,
84                               DBusError *opt_error,
85                               const char *arg_types,
86                               ...)
87 {
88     dbus_bool_t success;
89     va_list args;
90
91     va_start (args, arg_types);
92
93     success = dbind_connection_method_call_va
94         (cnx, bus_name, path, interface, method, opt_error, arg_types, args);
95
96     va_end (args);
97
98     return success;
99 }
100
101 static void set_reply (DBusPendingCall *pending, void *user_data)
102 {
103   void **replyptr = (void **)user_data;
104
105   *replyptr = dbus_pending_call_steal_reply (pending);
106 }
107
108 static DBusMessage *
109 send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout, DBusError *error)
110 {
111   DBusPendingCall *pending;
112   DBusMessage *reply = NULL;
113
114   if (!dbus_connection_send_with_reply (bus, message, &pending, timeout))
115   {
116     return NULL;
117   }
118   dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL);
119   while (!reply)
120   {
121     if (!dbus_connection_read_write_dispatch (bus, timeout)) return NULL;
122   }
123   return reply;
124 }
125
126 dbus_bool_t
127 dbind_connection_method_call_va (DBusConnection *cnx,
128                                  const char *bus_name,
129                                  const char *path,
130                                  const char *interface,
131                                  const char *method,
132                                  DBusError *opt_error,
133                                  const char *arg_types,
134                                  va_list     args)
135 {
136     dbus_bool_t success = FALSE;
137     DBusMessage *msg = NULL, *reply = NULL;
138     DBusError *err, real_err;
139     char *p;
140     char *dest;
141
142     if (opt_error)
143         err = opt_error;
144     else {
145         dbus_error_init (&real_err);
146         err = &real_err;
147     }
148
149     msg = dbus_message_new_method_call (bus_name, path, interface, method);
150     if (!msg)
151         goto out;
152     dbus_message_set_auto_start (msg, TRUE);
153
154     /* marshal */
155     p = (char *)arg_types;
156     {
157         DBusMessageIter iter;
158         
159         dbus_message_iter_init_append (msg, &iter);
160         /* special case base-types since we need to walk the stack worse-luck */
161         for (;*p != '\0' && *p != '=';) {
162             int intarg;
163             void *ptrarg;
164             double doublearg;
165             dbus_int64_t int64arg;
166             void *arg = NULL;
167
168             switch (*p) {
169             case DBUS_TYPE_BYTE:
170             case DBUS_TYPE_BOOLEAN:
171             case DBUS_TYPE_INT16:
172             case DBUS_TYPE_UINT16:
173             case DBUS_TYPE_INT32:
174             case DBUS_TYPE_UINT32:
175                 intarg = va_arg (args, int);
176                 arg = &intarg;
177                 break;
178             case DBUS_TYPE_INT64:
179             case DBUS_TYPE_UINT64:
180                 int64arg = va_arg (args, dbus_int64_t);
181                 arg = &int64arg;
182                 break;
183             case DBUS_TYPE_DOUBLE:
184                 doublearg = va_arg (args, double);
185                 arg = &doublearg;
186                 break;
187             /* ptr types */
188             case DBUS_TYPE_STRING:
189             case DBUS_TYPE_OBJECT_PATH:
190             case DBUS_TYPE_SIGNATURE:
191             case DBUS_TYPE_ARRAY:
192             case DBUS_TYPE_DICT_ENTRY:
193                 ptrarg = va_arg (args, void *);
194                 arg = &ptrarg;
195                 break;
196             case DBUS_STRUCT_BEGIN_CHAR:
197                 ptrarg = va_arg (args, void *);
198                 arg = ptrarg;
199                 break;
200
201             case DBUS_TYPE_VARIANT:
202                 fprintf (stderr, "No variant support yet - very toolkit specific\n");
203                 ptrarg = va_arg (args, void *);
204                 arg = &ptrarg;
205                 break;
206             default:
207                 fprintf (stderr, "Unknown / invalid arg type %c\n", *p);
208                 break;
209             }
210             if (arg != NULL)
211                 dbind_any_marshal (&iter, &p, &arg);
212             }
213     }
214
215     dest = dbus_message_get_destination(msg);
216     if (!dest)
217         goto out;
218     if (!strcmp (dbus_bus_get_unique_name(cnx), dest))
219     {
220       /* Can't use dbus_message_send_with_reply_and_block because it will
221        * not pass messages on to the provider side, causing deadlock */
222       reply = send_and_allow_reentry (cnx, msg, -1, err);
223     }
224     else
225     {
226       reply = dbus_connection_send_with_reply_and_block (cnx, msg, -1, err);
227     }
228     if (!reply)
229         goto out;
230
231     if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
232     {
233       char *name = dbus_message_get_error_name (reply);
234       dbus_set_error (err, name, g_strdup (""));
235       goto out;
236     }
237     /* demarshal */
238     if (p[0] == '=' && p[1] == '>')
239     {
240         DBusMessageIter iter;
241         p += 2;
242         dbus_message_iter_init (reply, &iter);
243         for (;*p != '\0';) {
244             void *arg = va_arg (args, void *);
245             dbind_any_demarshal (&iter, &p, &arg);
246         }
247     }
248
249     success = TRUE;
250 out:
251     if (msg)
252         dbus_message_unref (msg);
253
254     if (reply)
255         dbus_message_unref (reply);
256
257     if (err == &real_err)
258         dbus_error_free (err);
259
260     return success;
261 }
262