| |
1 /* |
| |
2 * gaim |
| |
3 * |
| |
4 * Gaim is the legal property of its developers, whose names are too numerous |
| |
5 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
6 * source distribution. |
| |
7 * |
| |
8 * This program is free software; you can redistribute it and/or modify |
| |
9 * it under the terms of the GNU General Public License as published by |
| |
10 * the Free Software Foundation; either version 2 of the License, or |
| |
11 * (at your option) any later version. |
| |
12 * |
| |
13 * This program is distributed in the hope that it will be useful, |
| |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
16 * GNU General Public License for more details. |
| |
17 * |
| |
18 * You should have received a copy of the GNU General Public License |
| |
19 * along with this program; if not, write to the Free Software |
| |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
21 * |
| |
22 */ |
| |
23 |
| |
24 #define DBUS_API_SUBJECT_TO_CHANGE |
| |
25 |
| |
26 #include <stdio.h> |
| |
27 #include <stdlib.h> |
| |
28 #include <string.h> |
| |
29 |
| |
30 #include "account.h" |
| |
31 #include "blist.h" |
| |
32 #include "conversation.h" |
| |
33 #include "dbus-gaim.h" |
| |
34 #include "dbus-server.h" |
| |
35 #include "dbus-useful.h" |
| |
36 #include "dbus-bindings.h" |
| |
37 #include "debug.h" |
| |
38 #include "core.h" |
| |
39 #include "internal.h" |
| |
40 #include "savedstatuses.h" |
| |
41 #include "value.h" |
| |
42 |
| |
43 |
| |
44 /**************************************************************************/ |
| |
45 /** @name Gaim DBUS pointer registration mechanism */ |
| |
46 /**************************************************************************/ |
| |
47 |
| |
48 /* |
| |
49 * Here we include the list of #GAIM_DBUS_DEFINE_TYPE statements for |
| |
50 * all structs defined in gaim. This file has been generated by the |
| |
51 * #dbus-analyze-types.py script. |
| |
52 */ |
| |
53 |
| |
54 #include "dbus-types.c" |
| |
55 |
| |
56 /* |
| |
57 * The following three hashtables map are used to translate between |
| |
58 * pointers (nodes) and the corresponding handles (ids). |
| |
59 */ |
| |
60 |
| |
61 static GHashTable *map_node_id; |
| |
62 static GHashTable *map_id_node; |
| |
63 static GHashTable *map_id_type; |
| |
64 |
| |
65 static gchar *init_error; |
| |
66 |
| |
67 /** |
| |
68 * This function initializes the pointer-id traslation system. It |
| |
69 * creates the three above hashtables and defines parents of some types. |
| |
70 */ |
| |
71 void |
| |
72 gaim_dbus_init_ids(void) |
| |
73 { |
| |
74 map_id_node = g_hash_table_new(g_direct_hash, g_direct_equal); |
| |
75 map_id_type = g_hash_table_new(g_direct_hash, g_direct_equal); |
| |
76 map_node_id = g_hash_table_new(g_direct_hash, g_direct_equal); |
| |
77 |
| |
78 GAIM_DBUS_TYPE(GaimBuddy)->parent = GAIM_DBUS_TYPE(GaimBlistNode); |
| |
79 GAIM_DBUS_TYPE(GaimContact)->parent = GAIM_DBUS_TYPE(GaimBlistNode); |
| |
80 GAIM_DBUS_TYPE(GaimChat)->parent = GAIM_DBUS_TYPE(GaimBlistNode); |
| |
81 GAIM_DBUS_TYPE(GaimGroup)->parent = GAIM_DBUS_TYPE(GaimBlistNode); |
| |
82 } |
| |
83 |
| |
84 void |
| |
85 gaim_dbus_register_pointer(gpointer node, GaimDBusType *type) |
| |
86 { |
| |
87 static gint last_id = 0; |
| |
88 |
| |
89 g_return_if_fail(map_node_id); |
| |
90 g_return_if_fail(g_hash_table_lookup(map_node_id, node) == NULL); |
| |
91 |
| |
92 last_id++; |
| |
93 g_hash_table_insert(map_node_id, node, GINT_TO_POINTER(last_id)); |
| |
94 g_hash_table_insert(map_id_node, GINT_TO_POINTER(last_id), node); |
| |
95 g_hash_table_insert(map_id_type, GINT_TO_POINTER(last_id), type); |
| |
96 } |
| |
97 |
| |
98 void |
| |
99 gaim_dbus_unregister_pointer(gpointer node) |
| |
100 { |
| |
101 gpointer id = g_hash_table_lookup(map_node_id, node); |
| |
102 |
| |
103 g_hash_table_remove(map_node_id, node); |
| |
104 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id)); |
| |
105 g_hash_table_remove(map_id_type, GINT_TO_POINTER(id)); |
| |
106 } |
| |
107 |
| |
108 gint |
| |
109 gaim_dbus_pointer_to_id(gpointer node) |
| |
110 { |
| |
111 gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node)); |
| |
112 if ((id == 0) && (node != NULL)) |
| |
113 { |
| |
114 gaim_debug_warning("dbus", |
| |
115 "Need to register an object with the dbus subsystem.\n"); |
| |
116 g_return_val_if_reached(0); |
| |
117 } |
| |
118 return id; |
| |
119 } |
| |
120 |
| |
121 gpointer |
| |
122 gaim_dbus_id_to_pointer(gint id, GaimDBusType *type) |
| |
123 { |
| |
124 GaimDBusType *objtype; |
| |
125 |
| |
126 objtype = (GaimDBusType*)g_hash_table_lookup(map_id_type, |
| |
127 GINT_TO_POINTER(id)); |
| |
128 |
| |
129 while (objtype != type && objtype != NULL) |
| |
130 objtype = objtype->parent; |
| |
131 |
| |
132 if (objtype == type) |
| |
133 return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id)); |
| |
134 else |
| |
135 return NULL; |
| |
136 } |
| |
137 |
| |
138 gint |
| |
139 gaim_dbus_pointer_to_id_error(gpointer ptr, DBusError *error) |
| |
140 { |
| |
141 gint id = gaim_dbus_pointer_to_id(ptr); |
| |
142 |
| |
143 if (ptr != NULL && id == 0) |
| |
144 dbus_set_error(error, "net.sf.gaim.ObjectNotFound", |
| |
145 "The return object is not mapped (this is a Gaim error)"); |
| |
146 |
| |
147 return id; |
| |
148 } |
| |
149 |
| |
150 gpointer |
| |
151 gaim_dbus_id_to_pointer_error(gint id, GaimDBusType *type, |
| |
152 const char *typename, DBusError *error) |
| |
153 { |
| |
154 gpointer ptr = gaim_dbus_id_to_pointer(id, type); |
| |
155 |
| |
156 if (ptr == NULL && id != 0) |
| |
157 dbus_set_error(error, "net.sf.gaim.InvalidHandle", |
| |
158 "%s object with ID = %i not found", typename, id); |
| |
159 |
| |
160 return ptr; |
| |
161 } |
| |
162 |
| |
163 |
| |
164 /**************************************************************************/ |
| |
165 /** @name Modified versions of some DBus functions */ |
| |
166 /**************************************************************************/ |
| |
167 |
| |
168 dbus_bool_t |
| |
169 gaim_dbus_message_get_args(DBusMessage *message, |
| |
170 DBusError *error, int first_arg_type, ...) |
| |
171 { |
| |
172 dbus_bool_t retval; |
| |
173 va_list var_args; |
| |
174 |
| |
175 va_start(var_args, first_arg_type); |
| |
176 retval = gaim_dbus_message_get_args_valist(message, error, first_arg_type, var_args); |
| |
177 va_end(var_args); |
| |
178 |
| |
179 return retval; |
| |
180 } |
| |
181 |
| |
182 dbus_bool_t |
| |
183 gaim_dbus_message_get_args_valist(DBusMessage *message, |
| |
184 DBusError *error, int first_arg_type, va_list var_args) |
| |
185 { |
| |
186 DBusMessageIter iter; |
| |
187 |
| |
188 dbus_message_iter_init(message, &iter); |
| |
189 return gaim_dbus_message_iter_get_args_valist(&iter, error, first_arg_type, var_args); |
| |
190 } |
| |
191 |
| |
192 dbus_bool_t |
| |
193 gaim_dbus_message_iter_get_args(DBusMessageIter *iter, |
| |
194 DBusError *error, int first_arg_type, ...) |
| |
195 { |
| |
196 dbus_bool_t retval; |
| |
197 va_list var_args; |
| |
198 |
| |
199 va_start(var_args, first_arg_type); |
| |
200 retval = gaim_dbus_message_iter_get_args_valist(iter, error, first_arg_type, var_args); |
| |
201 va_end(var_args); |
| |
202 |
| |
203 return retval; |
| |
204 } |
| |
205 |
| |
206 #define TYPE_IS_CONTAINER(typecode) \ |
| |
207 ((typecode) == DBUS_TYPE_STRUCT || \ |
| |
208 (typecode) == DBUS_TYPE_DICT_ENTRY || \ |
| |
209 (typecode) == DBUS_TYPE_VARIANT || \ |
| |
210 (typecode) == DBUS_TYPE_ARRAY) |
| |
211 |
| |
212 |
| |
213 dbus_bool_t |
| |
214 gaim_dbus_message_iter_get_args_valist(DBusMessageIter *iter, |
| |
215 DBusError *error, int first_arg_type, va_list var_args) |
| |
216 { |
| |
217 int spec_type, msg_type, i; |
| |
218 |
| |
219 spec_type = first_arg_type; |
| |
220 |
| |
221 for (i = 0; spec_type != DBUS_TYPE_INVALID; i++) |
| |
222 { |
| |
223 msg_type = dbus_message_iter_get_arg_type(iter); |
| |
224 |
| |
225 if (msg_type != spec_type) |
| |
226 { |
| |
227 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, |
| |
228 "Argument %d is specified to be of type \"%i\", but " |
| |
229 "is actually of type \"%i\"\n", i, |
| |
230 spec_type, msg_type); |
| |
231 return FALSE; |
| |
232 } |
| |
233 |
| |
234 if (!TYPE_IS_CONTAINER(spec_type)) |
| |
235 { |
| |
236 gpointer ptr; |
| |
237 ptr = va_arg (var_args, gpointer); |
| |
238 dbus_message_iter_get_basic(iter, ptr); |
| |
239 } |
| |
240 else |
| |
241 { |
| |
242 DBusMessageIter *sub; |
| |
243 sub = va_arg (var_args, DBusMessageIter*); |
| |
244 dbus_message_iter_recurse(iter, sub); |
| |
245 gaim_debug_info("dbus", "subiter %p:%p\n", sub, * (gpointer*) sub); |
| |
246 break; /* for testing only! */ |
| |
247 } |
| |
248 |
| |
249 spec_type = va_arg(var_args, int); |
| |
250 if (!dbus_message_iter_next(iter) && spec_type != DBUS_TYPE_INVALID) |
| |
251 { |
| |
252 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, |
| |
253 "Message has only %d arguments, but more were expected", i); |
| |
254 return FALSE; |
| |
255 } |
| |
256 } |
| |
257 |
| |
258 return TRUE; |
| |
259 } |
| |
260 |
| |
261 |
| |
262 |
| |
263 /**************************************************************************/ |
| |
264 /** @name Useful functions */ |
| |
265 /**************************************************************************/ |
| |
266 |
| |
267 const char *empty_to_null(const char *str) |
| |
268 { |
| |
269 if (str == NULL || str[0] == 0) |
| |
270 return NULL; |
| |
271 else |
| |
272 return str; |
| |
273 } |
| |
274 |
| |
275 const char * |
| |
276 null_to_empty(const char *s) |
| |
277 { |
| |
278 if (s) |
| |
279 return s; |
| |
280 else |
| |
281 return ""; |
| |
282 } |
| |
283 |
| |
284 dbus_int32_t * |
| |
285 gaim_dbusify_GList(GList *list, gboolean free_memory, dbus_int32_t *len) |
| |
286 { |
| |
287 dbus_int32_t *array; |
| |
288 int i; |
| |
289 GList *elem; |
| |
290 |
| |
291 *len = g_list_length(list); |
| |
292 array = g_new0(dbus_int32_t, g_list_length(list)); |
| |
293 for (i = 0, elem = list; elem != NULL; elem = elem->next, i++) |
| |
294 array[i] = gaim_dbus_pointer_to_id(elem->data); |
| |
295 |
| |
296 if (free_memory) |
| |
297 g_list_free(list); |
| |
298 |
| |
299 return array; |
| |
300 } |
| |
301 |
| |
302 dbus_int32_t * |
| |
303 gaim_dbusify_GSList(GSList *list, gboolean free_memory, dbus_int32_t *len) |
| |
304 { |
| |
305 dbus_int32_t *array; |
| |
306 int i; |
| |
307 GSList *elem; |
| |
308 |
| |
309 *len = g_slist_length(list); |
| |
310 array = g_new0(dbus_int32_t, g_slist_length(list)); |
| |
311 for (i = 0, elem = list; elem != NULL; elem = elem->next, i++) |
| |
312 array[i] = gaim_dbus_pointer_to_id(elem->data); |
| |
313 |
| |
314 if (free_memory) |
| |
315 g_slist_free(list); |
| |
316 |
| |
317 return array; |
| |
318 } |
| |
319 |
| |
320 gpointer * |
| |
321 gaim_GList_to_array(GList *list, gboolean free_memory, dbus_int32_t *len) |
| |
322 { |
| |
323 gpointer *array; |
| |
324 int i; |
| |
325 GList *elem; |
| |
326 |
| |
327 *len = g_list_length(list); |
| |
328 array = g_new0(gpointer, g_list_length(list)); |
| |
329 for (i = 0, elem = list; elem != NULL; elem = elem->next, i++) |
| |
330 array[i] = elem->data; |
| |
331 |
| |
332 if (free_memory) |
| |
333 g_list_free(list); |
| |
334 |
| |
335 return array; |
| |
336 } |
| |
337 |
| |
338 gpointer * |
| |
339 gaim_GSList_to_array(GSList *list, gboolean free_memory, dbus_int32_t *len) |
| |
340 { |
| |
341 gpointer *array; |
| |
342 int i; |
| |
343 GSList *elem; |
| |
344 |
| |
345 *len = g_slist_length(list); |
| |
346 array = g_new0(gpointer, g_slist_length(list)); |
| |
347 for (i = 0, elem = list; elem != NULL; elem = elem->next, i++) |
| |
348 array[i] = elem->data; |
| |
349 |
| |
350 if (free_memory) |
| |
351 g_slist_free(list); |
| |
352 |
| |
353 return array; |
| |
354 } |
| |
355 |
| |
356 GHashTable * |
| |
357 gaim_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error) |
| |
358 { |
| |
359 GHashTable *hash; |
| |
360 |
| |
361 /* we do not need to destroy strings because they are part of the message */ |
| |
362 hash = g_hash_table_new(g_str_hash, g_str_equal); |
| |
363 |
| |
364 do { |
| |
365 char *key, *value; |
| |
366 DBusMessageIter subiter; |
| |
367 |
| |
368 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) |
| |
369 goto error; |
| |
370 /* With all due respect to Dijkstra, |
| |
371 * this goto is for exception |
| |
372 * handling, and it is ok because it |
| |
373 * avoids duplication of the code |
| |
374 * responsible for destroying the hash |
| |
375 * table. Exceptional instructions |
| |
376 * for exceptional situations. |
| |
377 */ |
| |
378 |
| |
379 dbus_message_iter_recurse(iter, &subiter); |
| |
380 if (!gaim_dbus_message_iter_get_args(&subiter, error, |
| |
381 DBUS_TYPE_STRING, &key, |
| |
382 DBUS_TYPE_STRING, &value, |
| |
383 DBUS_TYPE_INVALID)) |
| |
384 goto error; /* same here */ |
| |
385 |
| |
386 g_hash_table_insert(hash, key, value); |
| |
387 } while (dbus_message_iter_next(iter)); |
| |
388 |
| |
389 return hash; |
| |
390 |
| |
391 error: |
| |
392 g_hash_table_destroy(hash); |
| |
393 return NULL; |
| |
394 } |
| |
395 |
| |
396 /**************************************************************/ |
| |
397 /* DBus bindings ... */ |
| |
398 /**************************************************************/ |
| |
399 |
| |
400 static DBusConnection *gaim_dbus_connection; |
| |
401 |
| |
402 DBusConnection * |
| |
403 gaim_dbus_get_connection(void) |
| |
404 { |
| |
405 return gaim_dbus_connection; |
| |
406 } |
| |
407 |
| |
408 #include "dbus-bindings.c" |
| |
409 |
| |
410 static gboolean |
| |
411 gaim_dbus_dispatch_cb(DBusConnection *connection, |
| |
412 DBusMessage *message, void *user_data) |
| |
413 { |
| |
414 const char *name; |
| |
415 GaimDBusBinding *bindings; |
| |
416 int i; |
| |
417 |
| |
418 bindings = (GaimDBusBinding*) user_data; |
| |
419 |
| |
420 if (!dbus_message_has_path(message, DBUS_PATH_GAIM)) |
| |
421 return FALSE; |
| |
422 |
| |
423 name = dbus_message_get_member(message); |
| |
424 |
| |
425 if (name == NULL) |
| |
426 return FALSE; |
| |
427 |
| |
428 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) |
| |
429 return FALSE; |
| |
430 |
| |
431 for (i = 0; bindings[i].name; i++) |
| |
432 if (!strcmp(name, bindings[i].name)) |
| |
433 { |
| |
434 DBusMessage *reply; |
| |
435 DBusError error; |
| |
436 |
| |
437 dbus_error_init(&error); |
| |
438 |
| |
439 reply = bindings[i].handler(message, &error); |
| |
440 |
| |
441 if (reply == NULL && dbus_error_is_set(&error)) |
| |
442 reply = dbus_message_new_error (message, |
| |
443 error.name, error.message); |
| |
444 |
| |
445 if (reply != NULL) |
| |
446 { |
| |
447 dbus_connection_send(connection, reply, NULL); |
| |
448 dbus_message_unref(reply); |
| |
449 } |
| |
450 |
| |
451 return TRUE; /* return reply! */ |
| |
452 } |
| |
453 |
| |
454 return FALSE; |
| |
455 } |
| |
456 |
| |
457 |
| |
458 static const char * |
| |
459 dbus_gettext(const char **ptr) |
| |
460 { |
| |
461 const char *text = *ptr; |
| |
462 *ptr += strlen(text) + 1; |
| |
463 return text; |
| |
464 } |
| |
465 |
| |
466 static void |
| |
467 gaim_dbus_introspect_cb(GList **bindings_list, void *bindings) |
| |
468 { |
| |
469 *bindings_list = g_list_prepend(*bindings_list, bindings); |
| |
470 } |
| |
471 |
| |
472 static DBusMessage *gaim_dbus_introspect(DBusMessage *message) |
| |
473 { |
| |
474 DBusMessage *reply; |
| |
475 GString *str; |
| |
476 GList *bindings_list, *node; |
| |
477 |
| |
478 str = g_string_sized_new(0x1000); /* TODO: why this size? */ |
| |
479 |
| |
480 g_string_append(str, "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"); |
| |
481 g_string_append_printf(str, "<node name='%s'>\n", DBUS_PATH_GAIM); |
| |
482 g_string_append_printf(str, "<interface name='%s'>\n", DBUS_INTERFACE_GAIM); |
| |
483 |
| |
484 bindings_list = NULL; |
| |
485 gaim_signal_emit(gaim_dbus_get_handle(), "dbus-introspect", &bindings_list); |
| |
486 |
| |
487 for (node = bindings_list; node; node = node->next) |
| |
488 { |
| |
489 GaimDBusBinding *bindings; |
| |
490 int i; |
| |
491 |
| |
492 bindings = (GaimDBusBinding*)node->data; |
| |
493 |
| |
494 for (i = 0; bindings[i].name; i++) |
| |
495 { |
| |
496 const char *text; |
| |
497 |
| |
498 g_string_append_printf(str, "<method name='%s'>\n", bindings[i].name); |
| |
499 |
| |
500 text = bindings[i].parameters; |
| |
501 while (*text) |
| |
502 { |
| |
503 const char *name, *direction, *type; |
| |
504 |
| |
505 direction = dbus_gettext(&text); |
| |
506 type = dbus_gettext(&text); |
| |
507 name = dbus_gettext(&text); |
| |
508 |
| |
509 g_string_append_printf(str, |
| |
510 "<arg name='%s' type='%s' direction='%s'/>\n", |
| |
511 name, type, direction); |
| |
512 } |
| |
513 g_string_append(str, "</method>\n"); |
| |
514 } |
| |
515 } |
| |
516 |
| |
517 g_string_append(str, "</interface>\n</node>\n"); |
| |
518 |
| |
519 reply = dbus_message_new_method_return(message); |
| |
520 dbus_message_append_args(reply, DBUS_TYPE_STRING, &(str->str), |
| |
521 DBUS_TYPE_INVALID); |
| |
522 g_string_free(str, TRUE); |
| |
523 g_list_free(bindings_list); |
| |
524 |
| |
525 return reply; |
| |
526 } |
| |
527 |
| |
528 static DBusHandlerResult |
| |
529 gaim_dbus_dispatch(DBusConnection *connection, |
| |
530 DBusMessage *message, void *user_data) |
| |
531 { |
| |
532 if (gaim_signal_emit_return_1(gaim_dbus_get_handle(), |
| |
533 "dbus-method-called", connection, message)) |
| |
534 return DBUS_HANDLER_RESULT_HANDLED; |
| |
535 |
| |
536 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL && |
| |
537 dbus_message_has_path(message, DBUS_PATH_GAIM) && |
| |
538 dbus_message_has_interface(message, DBUS_INTERFACE_INTROSPECTABLE) && |
| |
539 dbus_message_has_member(message, "Introspect")) |
| |
540 { |
| |
541 DBusMessage *reply; |
| |
542 reply = gaim_dbus_introspect(message); |
| |
543 dbus_connection_send (connection, reply, NULL); |
| |
544 dbus_message_unref(reply); |
| |
545 return DBUS_HANDLER_RESULT_HANDLED; |
| |
546 } |
| |
547 |
| |
548 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| |
549 } |
| |
550 |
| |
551 void |
| |
552 gaim_dbus_register_bindings(void *handle, GaimDBusBinding *bindings) |
| |
553 { |
| |
554 gaim_signal_connect(gaim_dbus_get_handle(), "dbus-method-called", |
| |
555 handle, |
| |
556 GAIM_CALLBACK(gaim_dbus_dispatch_cb), |
| |
557 bindings); |
| |
558 gaim_signal_connect(gaim_dbus_get_handle(), "dbus-introspect", |
| |
559 handle, |
| |
560 GAIM_CALLBACK(gaim_dbus_introspect_cb), |
| |
561 bindings); |
| |
562 } |
| |
563 |
| |
564 static void |
| |
565 gaim_dbus_dispatch_init(void) |
| |
566 { |
| |
567 static DBusObjectPathVTable vtable = {NULL, &gaim_dbus_dispatch, NULL, NULL, NULL, NULL}; |
| |
568 DBusError error; |
| |
569 int result; |
| |
570 |
| |
571 dbus_error_init(&error); |
| |
572 gaim_dbus_connection = dbus_bus_get(DBUS_BUS_STARTER, &error); |
| |
573 |
| |
574 if (gaim_dbus_connection == NULL) |
| |
575 { |
| |
576 init_error = g_strdup_printf(N_("Failed to get connection: %s"), error.message); |
| |
577 dbus_error_free(&error); |
| |
578 return; |
| |
579 } |
| |
580 |
| |
581 if (!dbus_connection_register_object_path(gaim_dbus_connection, |
| |
582 DBUS_PATH_GAIM, &vtable, NULL)) |
| |
583 { |
| |
584 init_error = g_strdup_printf(N_("Failed to get name: %s"), error.name); |
| |
585 dbus_error_free(&error); |
| |
586 return; |
| |
587 } |
| |
588 |
| |
589 result = dbus_bus_request_name(gaim_dbus_connection, |
| |
590 DBUS_SERVICE_GAIM, 0, &error); |
| |
591 |
| |
592 if (dbus_error_is_set(&error)) |
| |
593 { |
| |
594 dbus_connection_unref(gaim_dbus_connection); |
| |
595 dbus_error_free(&error); |
| |
596 gaim_dbus_connection = NULL; |
| |
597 init_error = g_strdup_printf(N_("Failed to get serv name: %s"), error.name); |
| |
598 return; |
| |
599 } |
| |
600 |
| |
601 dbus_connection_setup_with_g_main(gaim_dbus_connection, NULL); |
| |
602 |
| |
603 gaim_debug_misc("dbus", "okkk\n"); |
| |
604 |
| |
605 gaim_signal_register(gaim_dbus_get_handle(), "dbus-method-called", |
| |
606 gaim_marshal_BOOLEAN__POINTER_POINTER, |
| |
607 gaim_value_new(GAIM_TYPE_BOOLEAN), 2, |
| |
608 gaim_value_new(GAIM_TYPE_POINTER), |
| |
609 gaim_value_new(GAIM_TYPE_POINTER)); |
| |
610 |
| |
611 gaim_signal_register(gaim_dbus_get_handle(), "dbus-introspect", |
| |
612 gaim_marshal_VOID__POINTER, NULL, 1, |
| |
613 gaim_value_new_outgoing(GAIM_TYPE_POINTER)); |
| |
614 |
| |
615 GAIM_DBUS_REGISTER_BINDINGS(gaim_dbus_get_handle()); |
| |
616 } |
| |
617 |
| |
618 |
| |
619 |
| |
620 /**************************************************************************/ |
| |
621 /** @name Signals */ |
| |
622 /**************************************************************************/ |
| |
623 |
| |
624 |
| |
625 |
| |
626 static char * |
| |
627 gaim_dbus_convert_signal_name(const char *gaim_name) |
| |
628 { |
| |
629 int gaim_index, g_index; |
| |
630 char *g_name = g_new(char, strlen(gaim_name) + 1); |
| |
631 gboolean capitalize_next = TRUE; |
| |
632 |
| |
633 for (gaim_index = g_index = 0; gaim_name[gaim_index]; gaim_index++) |
| |
634 if (gaim_name[gaim_index] != '-' && gaim_name[gaim_index] != '_') |
| |
635 { |
| |
636 if (capitalize_next) |
| |
637 g_name[g_index++] = g_ascii_toupper(gaim_name[gaim_index]); |
| |
638 else |
| |
639 g_name[g_index++] = gaim_name[gaim_index]; |
| |
640 capitalize_next = FALSE; |
| |
641 } else |
| |
642 capitalize_next = TRUE; |
| |
643 |
| |
644 g_name[g_index] = 0; |
| |
645 |
| |
646 return g_name; |
| |
647 } |
| |
648 |
| |
649 #define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type)) |
| |
650 |
| |
651 static void |
| |
652 gaim_dbus_message_append_gaim_values(DBusMessageIter *iter, |
| |
653 int number, GaimValue **gaim_values, va_list data) |
| |
654 { |
| |
655 int i; |
| |
656 |
| |
657 for (i = 0; i < number; i++) |
| |
658 { |
| |
659 const char *str; |
| |
660 int id; |
| |
661 gint xint; |
| |
662 guint xuint; |
| |
663 gboolean xboolean; |
| |
664 gpointer ptr = NULL; |
| |
665 |
| |
666 if (gaim_value_is_outgoing(gaim_values[i])) |
| |
667 { |
| |
668 ptr = my_arg(gpointer); |
| |
669 g_return_if_fail(ptr); |
| |
670 } |
| |
671 |
| |
672 switch (gaim_values[i]->type) |
| |
673 { |
| |
674 case GAIM_TYPE_INT: |
| |
675 xint = my_arg(gint); |
| |
676 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint); |
| |
677 break; |
| |
678 case GAIM_TYPE_UINT: |
| |
679 xuint = my_arg(guint); |
| |
680 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint); |
| |
681 break; |
| |
682 case GAIM_TYPE_BOOLEAN: |
| |
683 xboolean = my_arg(gboolean); |
| |
684 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean); |
| |
685 break; |
| |
686 case GAIM_TYPE_STRING: |
| |
687 str = null_to_empty(my_arg(char*)); |
| |
688 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str); |
| |
689 break; |
| |
690 case GAIM_TYPE_SUBTYPE: /* registered pointers only! */ |
| |
691 case GAIM_TYPE_POINTER: |
| |
692 case GAIM_TYPE_OBJECT: |
| |
693 case GAIM_TYPE_BOXED: |
| |
694 id = gaim_dbus_pointer_to_id(my_arg(gpointer)); |
| |
695 dbus_message_iter_append_basic(iter, |
| |
696 (sizeof(void *) == 4) ? DBUS_TYPE_UINT32 : DBUS_TYPE_UINT64, &id); |
| |
697 break; |
| |
698 default: /* no conversion implemented */ |
| |
699 g_return_if_reached(); |
| |
700 } |
| |
701 } |
| |
702 } |
| |
703 |
| |
704 #undef my_arg |
| |
705 |
| |
706 void |
| |
707 gaim_dbus_signal_emit_gaim(const char *name, int num_values, |
| |
708 GaimValue **values, va_list vargs) |
| |
709 { |
| |
710 DBusMessage *signal; |
| |
711 DBusMessageIter iter; |
| |
712 char *newname; |
| |
713 |
| |
714 #if 0 /* this is noisy with no dbus connection */ |
| |
715 g_return_if_fail(gaim_dbus_connection); |
| |
716 #else |
| |
717 if (gaim_dbus_connection == NULL) |
| |
718 return; |
| |
719 #endif |
| |
720 |
| |
721 |
| |
722 /* |
| |
723 * The test below is a hack that prevents our "dbus-method-called" |
| |
724 * signal from being propagated to dbus. What we really need is a |
| |
725 * flag for each signal that states whether this signal is to be |
| |
726 * dbus-propagated or not. |
| |
727 */ |
| |
728 if (!strcmp(name, "dbus-method-called")) |
| |
729 return; |
| |
730 |
| |
731 newname = gaim_dbus_convert_signal_name(name); |
| |
732 signal = dbus_message_new_signal(DBUS_PATH_GAIM, DBUS_INTERFACE_GAIM, newname); |
| |
733 dbus_message_iter_init_append(signal, &iter); |
| |
734 |
| |
735 gaim_dbus_message_append_gaim_values(&iter, num_values, values, vargs); |
| |
736 |
| |
737 dbus_connection_send(gaim_dbus_connection, signal, NULL); |
| |
738 |
| |
739 g_free(newname); |
| |
740 dbus_message_unref(signal); |
| |
741 } |
| |
742 |
| |
743 const char * |
| |
744 gaim_dbus_get_init_error(void) |
| |
745 { |
| |
746 return init_error; |
| |
747 } |
| |
748 |
| |
749 void * |
| |
750 gaim_dbus_get_handle(void) |
| |
751 { |
| |
752 static int handle; |
| |
753 |
| |
754 return &handle; |
| |
755 } |
| |
756 |
| |
757 void |
| |
758 gaim_dbus_init(void) |
| |
759 { |
| |
760 if (g_thread_supported()) |
| |
761 dbus_g_thread_init(); |
| |
762 |
| |
763 gaim_dbus_init_ids(); |
| |
764 |
| |
765 g_free(init_error); |
| |
766 init_error = NULL; |
| |
767 gaim_dbus_dispatch_init(); |
| |
768 if (init_error != NULL) |
| |
769 gaim_debug_error("dbus", "%s\n", init_error); |
| |
770 } |
| |
771 |
| |
772 void |
| |
773 gaim_dbus_uninit(void) |
| |
774 { |
| |
775 /* Surely we must do SOME kind of uninitialization? */ |
| |
776 |
| |
777 g_free(init_error); |
| |
778 init_error = NULL; |
| |
779 } |