comparison libpurple/dbus-server.c @ 15374:5fe8042783c1

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