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