Mercurial > pidgin.yaz
annotate libgaim/dbus-server.c @ 14455:c2c916d4d95c
[gaim-migrate @ 17169]
Remove VERSION file from svn, it was only needed there for wingaim and was causing problems elsewhere when it was not overwritten.
Parse the version number from the configure.ac file for the wingaim build instead.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Tue, 05 Sep 2006 16:13:57 +0000 |
parents | 9c884b84afb9 |
children | 64733c315986 |
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 | |
582 if (!dbus_connection_register_object_path(gaim_dbus_connection, | |
583 DBUS_PATH_GAIM, &vtable, NULL)) | |
584 { | |
585 init_error = g_strdup_printf(N_("Failed to get name: %s"), error.name); | |
586 dbus_error_free(&error); | |
587 return; | |
588 } | |
589 | |
590 result = dbus_bus_request_name(gaim_dbus_connection, | |
591 DBUS_SERVICE_GAIM, 0, &error); | |
592 | |
593 if (dbus_error_is_set(&error)) | |
594 { | |
595 dbus_connection_unref(gaim_dbus_connection); | |
596 dbus_error_free(&error); | |
597 gaim_dbus_connection = NULL; | |
598 init_error = g_strdup_printf(N_("Failed to get serv name: %s"), error.name); | |
599 return; | |
600 } | |
601 | |
602 dbus_connection_setup_with_g_main(gaim_dbus_connection, NULL); | |
603 | |
604 gaim_debug_misc("dbus", "okkk\n"); | |
605 | |
606 gaim_signal_register(gaim_dbus_get_handle(), "dbus-method-called", | |
607 gaim_marshal_BOOLEAN__POINTER_POINTER, | |
608 gaim_value_new(GAIM_TYPE_BOOLEAN), 2, | |
609 gaim_value_new(GAIM_TYPE_POINTER), | |
610 gaim_value_new(GAIM_TYPE_POINTER)); | |
611 | |
612 gaim_signal_register(gaim_dbus_get_handle(), "dbus-introspect", | |
613 gaim_marshal_VOID__POINTER, NULL, 1, | |
614 gaim_value_new_outgoing(GAIM_TYPE_POINTER)); | |
615 | |
616 GAIM_DBUS_REGISTER_BINDINGS(gaim_dbus_get_handle()); | |
617 } | |
618 | |
619 | |
620 | |
621 /**************************************************************************/ | |
622 /** @name Signals */ | |
623 /**************************************************************************/ | |
624 | |
625 | |
626 | |
627 static char * | |
628 gaim_dbus_convert_signal_name(const char *gaim_name) | |
629 { | |
630 int gaim_index, g_index; | |
631 char *g_name = g_new(char, strlen(gaim_name) + 1); | |
632 gboolean capitalize_next = TRUE; | |
633 | |
634 for (gaim_index = g_index = 0; gaim_name[gaim_index]; gaim_index++) | |
635 if (gaim_name[gaim_index] != '-' && gaim_name[gaim_index] != '_') | |
636 { | |
637 if (capitalize_next) | |
638 g_name[g_index++] = g_ascii_toupper(gaim_name[gaim_index]); | |
639 else | |
640 g_name[g_index++] = gaim_name[gaim_index]; | |
641 capitalize_next = FALSE; | |
642 } else | |
643 capitalize_next = TRUE; | |
644 | |
645 g_name[g_index] = 0; | |
646 | |
647 return g_name; | |
648 } | |
649 | |
650 #define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type)) | |
651 | |
652 static void | |
653 gaim_dbus_message_append_gaim_values(DBusMessageIter *iter, | |
654 int number, GaimValue **gaim_values, va_list data) | |
655 { | |
656 int i; | |
657 | |
658 for (i = 0; i < number; i++) | |
659 { | |
660 const char *str; | |
661 int id; | |
662 gint xint; | |
663 guint xuint; | |
664 gboolean xboolean; | |
665 gpointer ptr = NULL; | |
666 | |
667 if (gaim_value_is_outgoing(gaim_values[i])) | |
668 { | |
669 ptr = my_arg(gpointer); | |
670 g_return_if_fail(ptr); | |
671 } | |
672 | |
673 switch (gaim_values[i]->type) | |
674 { | |
675 case GAIM_TYPE_INT: | |
676 xint = my_arg(gint); | |
677 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint); | |
678 break; | |
679 case GAIM_TYPE_UINT: | |
680 xuint = my_arg(guint); | |
681 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint); | |
682 break; | |
683 case GAIM_TYPE_BOOLEAN: | |
684 xboolean = my_arg(gboolean); | |
685 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean); | |
686 break; | |
687 case GAIM_TYPE_STRING: | |
688 str = null_to_empty(my_arg(char*)); | |
689 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str); | |
690 break; | |
691 case GAIM_TYPE_SUBTYPE: /* registered pointers only! */ | |
692 case GAIM_TYPE_POINTER: | |
693 case GAIM_TYPE_OBJECT: | |
694 case GAIM_TYPE_BOXED: | |
695 id = gaim_dbus_pointer_to_id(my_arg(gpointer)); | |
696 dbus_message_iter_append_basic(iter, | |
697 (sizeof(void *) == 4) ? DBUS_TYPE_UINT32 : DBUS_TYPE_UINT64, &id); | |
698 break; | |
699 default: /* no conversion implemented */ | |
700 g_return_if_reached(); | |
701 } | |
702 } | |
703 } | |
704 | |
705 #undef my_arg | |
706 | |
707 void | |
708 gaim_dbus_signal_emit_gaim(const char *name, int num_values, | |
709 GaimValue **values, va_list vargs) | |
710 { | |
711 DBusMessage *signal; | |
712 DBusMessageIter iter; | |
713 char *newname; | |
714 | |
715 #if 0 /* this is noisy with no dbus connection */ | |
716 g_return_if_fail(gaim_dbus_connection); | |
717 #else | |
718 if (gaim_dbus_connection == NULL) | |
719 return; | |
720 #endif | |
721 | |
722 | |
723 /* | |
724 * The test below is a hack that prevents our "dbus-method-called" | |
725 * signal from being propagated to dbus. What we really need is a | |
726 * flag for each signal that states whether this signal is to be | |
727 * dbus-propagated or not. | |
728 */ | |
729 if (!strcmp(name, "dbus-method-called")) | |
730 return; | |
731 | |
732 newname = gaim_dbus_convert_signal_name(name); | |
733 signal = dbus_message_new_signal(DBUS_PATH_GAIM, DBUS_INTERFACE_GAIM, newname); | |
734 dbus_message_iter_init_append(signal, &iter); | |
735 | |
736 gaim_dbus_message_append_gaim_values(&iter, num_values, values, vargs); | |
737 | |
738 dbus_connection_send(gaim_dbus_connection, signal, NULL); | |
739 | |
740 g_free(newname); | |
741 dbus_message_unref(signal); | |
742 } | |
743 | |
744 const char * | |
745 gaim_dbus_get_init_error(void) | |
746 { | |
747 return init_error; | |
748 } | |
749 | |
750 void * | |
751 gaim_dbus_get_handle(void) | |
752 { | |
753 static int handle; | |
754 | |
755 return &handle; | |
756 } | |
757 | |
758 void | |
759 gaim_dbus_init(void) | |
760 { | |
761 gaim_dbus_init_ids(); | |
762 | |
763 g_free(init_error); | |
764 init_error = NULL; | |
765 gaim_dbus_dispatch_init(); | |
766 if (init_error != NULL) | |
767 gaim_debug_error("dbus", "%s\n", init_error); | |
768 } | |
769 | |
770 void | |
771 gaim_dbus_uninit(void) | |
772 { | |
773 /* Surely we must do SOME kind of uninitialization? */ | |
774 | |
775 g_free(init_error); | |
776 init_error = NULL; | |
777 } |