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