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