Mercurial > pidgin.yaz
comparison src/dbus-server.c @ 11067:2eca9ed49469
[gaim-migrate @ 13048]
Modified configure.ac so that it rejects dbus builds with the dbus
library older than 0.34
Added a simple object registration system to the dbus implementation
so that it is possible to query object properties remotely (eg. give
me property "name" of buddy with id = 5).
committer: Tailor Script <tailor@pidgin.im>
author | Piotr Zielinski <zielaj> |
---|---|
date | Thu, 07 Jul 2005 15:43:48 +0000 |
parents | df0241eb602c |
children | 9bd0aac996f4 |
comparison
equal
deleted
inserted
replaced
11066:2507d20c3d0b | 11067:2eca9ed49469 |
---|---|
29 #include <glib/gi18n.h> | 29 #include <glib/gi18n.h> |
30 #include <glib-object.h> | 30 #include <glib-object.h> |
31 #include <glib/gquark.h> | 31 #include <glib/gquark.h> |
32 | 32 |
33 #include "account.h" | 33 #include "account.h" |
34 #include "blist.h" | |
35 #include "conversation.h" | |
34 #include "dbus-gaim.h" | 36 #include "dbus-gaim.h" |
35 #include "dbus-server.h" | 37 #include "dbus-server.h" |
36 #include "debug.h" | 38 #include "debug.h" |
37 #include "core.h" | 39 #include "core.h" |
38 | 40 #include "value.h" |
39 /* GaimObject, basic definitions*/ | 41 |
42 /**************************************************************************/ | |
43 /** @name Lots of GObject crap I don't understand */ | |
44 /**************************************************************************/ | |
40 | 45 |
41 typedef struct GaimObject GaimObject; | 46 typedef struct GaimObject GaimObject; |
42 typedef struct GaimObjectClass GaimObjectClass; | 47 typedef struct GaimObjectClass GaimObjectClass; |
43 | 48 |
44 GType gaim_object_get_type(void); | 49 GType gaim_object_get_type(void); |
70 gaim_object_class_init(GaimObjectClass *mobject_class) | 75 gaim_object_class_init(GaimObjectClass *mobject_class) |
71 { | 76 { |
72 } | 77 } |
73 | 78 |
74 static GObject *gaim_object; | 79 static GObject *gaim_object; |
75 | 80 static GQuark gaim_object_error_quark; |
76 | 81 |
77 /* Implementations of remote DBUS calls */ | 82 |
78 | 83 |
84 /**************************************************************************/ | |
85 /** @name Utility functions */ | |
86 /**************************************************************************/ | |
87 | |
88 #define error_unless_1(condition, str, parameter) \ | |
89 if (!(condition)) { \ | |
90 g_set_error(error, gaim_object_error_quark, \ | |
91 DBUS_ERROR_NOT_FOUND, \ | |
92 str, parameter); \ | |
93 return FALSE; \ | |
94 } | |
95 | |
96 #define error_unless_2(condition, str, a,b) \ | |
97 if (!(condition)) { \ | |
98 g_set_error(error, gaim_object_error_quark, \ | |
99 DBUS_ERROR_NOT_FOUND, \ | |
100 str, a,b); \ | |
101 return FALSE; \ | |
102 } | |
103 | |
104 static const char* null_to_empty(const char *s) { | |
105 if (s) | |
106 return s; | |
107 else | |
108 return ""; | |
109 } | |
110 | |
111 typedef gboolean (*GaimNodeFilter)(GaimBlistNode *node, gpointer *user_data); | |
112 | |
113 static gboolean | |
114 filter_is_buddy(GaimBlistNode *node, gpointer *user_data) | |
115 { | |
116 return GAIM_BLIST_NODE_IS_BUDDY(node); | |
117 } | |
118 | |
119 static gboolean | |
120 filter_is_online_buddy(GaimBlistNode *node, | |
121 gpointer *user_data) | |
122 { | |
123 return GAIM_BLIST_NODE_IS_BUDDY(node) && | |
124 GAIM_BUDDY_IS_ONLINE((GaimBuddy *)node); | |
125 } | |
126 | |
127 | |
128 static GList* | |
129 get_buddy_list (GList *created_list, /**< can be NULL */ | |
130 GaimBlistNode *gaim_buddy_list, /**< can be NULL */ | |
131 GaimNodeFilter filter, | |
132 gpointer user_data) | |
133 { | |
134 GaimBlistNode *node; | |
135 | |
136 for(node = gaim_buddy_list; node; node = node->next) | |
137 { | |
138 if ((*filter)(node, user_data)) | |
139 created_list = g_list_prepend(created_list, node); | |
140 | |
141 created_list = get_buddy_list(created_list, node->child, | |
142 filter, user_data); | |
143 } | |
144 | |
145 return created_list; | |
146 } | |
147 | |
148 | |
149 | |
150 /**************************************************************************/ | |
151 /** @name Implementations of remote DBUS calls */ | |
152 /**************************************************************************/ | |
79 | 153 |
80 static gboolean | 154 static gboolean |
81 gaim_object_ping(GaimObject *obj, GError **error) | 155 gaim_object_ping(GaimObject *obj, GError **error) |
82 { | 156 { |
83 return TRUE; | 157 return TRUE; |
99 gaim_account_connect((GaimAccount*) cur->data); | 173 gaim_account_connect((GaimAccount*) cur->data); |
100 | 174 |
101 return TRUE; | 175 return TRUE; |
102 } | 176 } |
103 | 177 |
178 | |
179 | |
180 static gboolean | |
181 gaim_object_get_buddy_list (GaimObject *obj, GArray **out_buddy_ids, | |
182 GError **error) | |
183 { | |
184 GList *node; | |
185 GList *buddy_list = get_buddy_list(NULL, gaim_get_blist()->root, | |
186 &filter_is_buddy, NULL); | |
187 GArray *buddy_ids = g_array_new(FALSE, TRUE, sizeof(gint32));; | |
188 | |
189 buddy_list = g_list_reverse(buddy_list); | |
190 | |
191 for (node = buddy_list; node; node = node->next) { | |
192 gint32 id = gaim_dbus_pointer_to_id(node->data); | |
193 g_array_append_val(buddy_ids, id); | |
194 } | |
195 | |
196 g_list_free(buddy_list); | |
197 *out_buddy_ids = buddy_ids; | |
198 | |
199 return TRUE; | |
200 } | |
201 | |
202 | |
203 | |
204 | |
205 | |
206 static gboolean | |
207 gaim_object_find_account(GaimObject *unused, | |
208 const char *account_name, const char *protocol_name, | |
209 gint *account_id, GError **error) | |
210 { | |
211 GaimAccount *account = gaim_accounts_find(account_name, protocol_name); | |
212 | |
213 error_unless_2(account, "Account '%s' with protocol '%s' not found", | |
214 account_name, protocol_name); | |
215 | |
216 *account_id = gaim_dbus_pointer_to_id(account); | |
217 return TRUE; | |
218 } | |
219 | |
220 static gboolean | |
221 gaim_object_find_buddy(GaimObject *unused, gint account_id, const char *buddy_name, | |
222 gint *buddy_id, GError **error) | |
223 { | |
224 GaimAccount *account; | |
225 GaimBuddy *buddy; | |
226 | |
227 account = gaim_dbus_id_to_pointer(account_id, DBUS_POINTER_ACCOUNT); | |
228 error_unless_1(account, "Invalid account id: %i", account_id); | |
229 | |
230 buddy = gaim_find_buddy(account, buddy_name); | |
231 error_unless_1(account, "Buddy '%s' not found.", buddy_name); | |
232 | |
233 *buddy_id = gaim_dbus_pointer_to_id(buddy); | |
234 return TRUE; | |
235 } | |
236 | |
237 static gboolean | |
238 gaim_object_start_im_conversation (GaimObject *obj, gint buddy_id, GError **error) | |
239 { | |
240 GaimBuddy *buddy = (GaimBuddy*) gaim_dbus_id_to_pointer(buddy_id, | |
241 DBUS_POINTER_BUDDY); | |
242 | |
243 error_unless_1(buddy, "Invalid buddy id: %i", buddy_id); | |
244 | |
245 gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name); | |
246 | |
247 return TRUE; | |
248 } | |
249 | |
250 | |
251 | |
252 /**************************************************************************/ | |
253 /** @name Gaim DBUS property handling functions */ | |
254 /**************************************************************************/ | |
255 | |
256 | |
257 typedef struct _GaimDBusProperty { | |
258 char *name; | |
259 gint offset; | |
260 GaimType type; | |
261 } GaimDBusProperty; | |
262 | |
263 /* change GAIM_TYPE into G_TYPE */ | |
264 | |
265 static gboolean | |
266 gaim_dbus_get_property(GaimDBusProperty *list, int list_len, | |
267 gpointer data, const char *name, | |
268 GValue *value, GError **error) | |
269 { | |
270 int i; | |
271 | |
272 for(i=0; i<list_len; i++) { | |
273 if (!strcmp(list[i].name, name)) { | |
274 gpointer ptr = G_STRUCT_MEMBER_P(data, list[i].offset); | |
275 switch(list[i].type) { | |
276 case GAIM_TYPE_STRING: | |
277 g_value_init(value, G_TYPE_STRING); | |
278 g_value_set_string (value, g_strdup(null_to_empty(*(char **)ptr))); | |
279 break; | |
280 | |
281 case GAIM_TYPE_INT: | |
282 g_value_init(value, G_TYPE_INT); | |
283 g_value_set_int (value, *(int*) ptr); | |
284 break; | |
285 | |
286 case GAIM_TYPE_BOOLEAN: | |
287 g_value_init(value, G_TYPE_BOOLEAN); | |
288 g_value_set_int (value, *(gboolean*) ptr); | |
289 break; | |
290 | |
291 case GAIM_TYPE_POINTER: /* registered pointers only! */ | |
292 g_value_init(value, G_TYPE_INT); | |
293 g_value_set_int (value, | |
294 gaim_dbus_pointer_to_id (*(gpointer *)ptr)); | |
295 break; | |
296 default: | |
297 g_assert_not_reached(); | |
298 } | |
299 return TRUE; | |
300 } | |
301 } | |
302 | |
303 g_value_init(value, G_TYPE_INT); | |
304 g_value_set_int(value, 0); | |
305 error_unless_1(FALSE, "Invalid property '%s'", name); | |
306 } | |
307 | |
308 | |
309 #define DECLARE_PROPERTY(maintype, name, type) {#name, G_STRUCT_OFFSET(maintype, name), type} | |
310 | |
311 GaimDBusProperty buddy_properties [] = { | |
312 DECLARE_PROPERTY(GaimBuddy, name, GAIM_TYPE_STRING), | |
313 DECLARE_PROPERTY(GaimBuddy, alias, GAIM_TYPE_STRING), | |
314 DECLARE_PROPERTY(GaimBuddy, server_alias, GAIM_TYPE_STRING), | |
315 DECLARE_PROPERTY(GaimBuddy, account, GAIM_TYPE_POINTER) | |
316 }; | |
317 | |
318 GaimDBusProperty account_properties [] = { | |
319 DECLARE_PROPERTY(GaimAccount, username, GAIM_TYPE_STRING), | |
320 DECLARE_PROPERTY(GaimAccount, alias, GAIM_TYPE_STRING), | |
321 DECLARE_PROPERTY(GaimAccount, user_info, GAIM_TYPE_STRING), | |
322 DECLARE_PROPERTY(GaimAccount, protocol_id, GAIM_TYPE_STRING), | |
323 }; | |
324 | |
325 GaimDBusProperty contact_properties [] = { | |
326 DECLARE_PROPERTY(GaimContact, alias, GAIM_TYPE_STRING), | |
327 DECLARE_PROPERTY(GaimContact, totalsize, GAIM_TYPE_INT), | |
328 DECLARE_PROPERTY(GaimContact, currentsize, GAIM_TYPE_INT), | |
329 DECLARE_PROPERTY(GaimContact, online, GAIM_TYPE_INT), | |
330 DECLARE_PROPERTY(GaimContact, priority, GAIM_TYPE_POINTER), | |
331 DECLARE_PROPERTY(GaimContact, priority_valid, GAIM_TYPE_BOOLEAN), | |
332 }; | |
333 | |
334 GaimDBusProperty group_properties [] = { | |
335 DECLARE_PROPERTY(GaimGroup, name, GAIM_TYPE_STRING), | |
336 DECLARE_PROPERTY(GaimGroup, totalsize, GAIM_TYPE_INT), | |
337 DECLARE_PROPERTY(GaimGroup, currentsize, GAIM_TYPE_INT), | |
338 DECLARE_PROPERTY(GaimGroup, online, GAIM_TYPE_INT), | |
339 }; | |
340 | |
341 GaimDBusProperty chat_properties [] = { | |
342 DECLARE_PROPERTY(GaimChat, alias, GAIM_TYPE_STRING), | |
343 DECLARE_PROPERTY(GaimChat, account, GAIM_TYPE_POINTER), | |
344 }; | |
345 | |
346 | |
347 #define DECLARE_PROPERTY_HANDLER(type, gaim_type) \ | |
348 static gboolean \ | |
349 gaim_object_get_##type##_property (GaimObject *unused, \ | |
350 gint id, const char *property_name, \ | |
351 GValue *value, GError **error) \ | |
352 { \ | |
353 gpointer object = gaim_dbus_id_to_pointer(id, gaim_type); \ | |
354 \ | |
355 error_unless_1(object, "Invalid " #type " id: %i", id); \ | |
356 \ | |
357 return gaim_dbus_get_property(type##_properties, \ | |
358 G_N_ELEMENTS(type##_properties), \ | |
359 object, property_name, value, error); \ | |
360 } | |
361 | |
362 DECLARE_PROPERTY_HANDLER(buddy, DBUS_POINTER_BUDDY) | |
363 DECLARE_PROPERTY_HANDLER(account, DBUS_POINTER_ACCOUNT) | |
364 DECLARE_PROPERTY_HANDLER(contact, DBUS_POINTER_ACCOUNT) | |
365 DECLARE_PROPERTY_HANDLER(group, DBUS_POINTER_ACCOUNT) | |
366 DECLARE_PROPERTY_HANDLER(chat, DBUS_POINTER_ACCOUNT) | |
367 | |
104 #include "dbus-server-bindings.c" | 368 #include "dbus-server-bindings.c" |
369 | |
370 | |
371 | |
372 /**************************************************************************/ | |
373 /** @name Gaim DBUS pointer registration mechanism */ | |
374 /**************************************************************************/ | |
375 | |
376 static GHashTable *map_id_node; | |
377 static GHashTable *map_id_type; | |
378 static GHashTable *map_node_id; | |
379 | |
380 void gaim_dbus_init_ids(void) { | |
381 map_id_node = g_hash_table_new (g_direct_hash, g_direct_equal); | |
382 map_id_type = g_hash_table_new (g_direct_hash, g_direct_equal); | |
383 map_node_id = g_hash_table_new (g_direct_hash, g_direct_equal); | |
384 } | |
385 | |
386 void gaim_dbus_register_pointer(gpointer node, GaimDBusPointerType type) | |
387 { | |
388 static gint last_id = 0; | |
389 g_assert(g_hash_table_lookup(map_node_id, node) == NULL); | |
390 | |
391 | |
392 last_id++; | |
393 g_hash_table_insert(map_node_id, node, GINT_TO_POINTER(last_id)); | |
394 g_hash_table_insert(map_id_node, GINT_TO_POINTER(last_id), node); | |
395 g_hash_table_insert(map_id_type, GINT_TO_POINTER(last_id), | |
396 GINT_TO_POINTER(type)); | |
397 } | |
398 | |
399 | |
400 void gaim_dbus_unregister_pointer(gpointer node) { | |
401 gpointer id = g_hash_table_lookup(map_node_id, node); | |
402 | |
403 g_hash_table_remove(map_node_id, node); | |
404 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id)); | |
405 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id)); | |
406 } | |
407 | |
408 gint gaim_dbus_pointer_to_id(gpointer node) { | |
409 gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node)); | |
410 g_assert(id); | |
411 return id; | |
412 } | |
413 | |
414 gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type) { | |
415 if (type != GPOINTER_TO_INT(g_hash_table_lookup(map_id_type, | |
416 GINT_TO_POINTER(id)))) | |
417 return NULL; | |
418 return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id)); | |
419 } | |
420 | |
421 | |
422 | |
423 /**************************************************************************/ | |
424 /** @name Gaim DBUS init function */ | |
425 /**************************************************************************/ | |
105 | 426 |
106 | 427 |
107 gboolean | 428 gboolean |
108 dbus_server_init(void) | 429 dbus_server_init(void) |
109 { | 430 { |
110 DBusGConnection *connection; | 431 DBusGConnection *connection; |
111 GError *error; | 432 GError *error = NULL; |
112 DBusGProxy *driver_proxy; | 433 DBusGProxy *driver_proxy; |
113 guint32 request_name_ret; | 434 guint32 request_name_ret; |
114 | 435 |
436 gaim_object_error_quark = | |
437 g_quark_from_static_string("org.gaim.GaimError"); | |
438 | |
115 gaim_debug_misc("dbus", "launching dbus server\n"); | 439 gaim_debug_misc("dbus", "launching dbus server\n"); |
116 | 440 |
117 /* Connect to the bus */ | 441 /* Connect to the bus */ |
118 | 442 |
119 error = NULL; | 443 error = NULL; |
120 connection = dbus_g_bus_get(DBUS_BUS_STARTER, &error); | 444 connection = dbus_g_bus_get(DBUS_BUS_STARTER, &error); |
121 | 445 |
122 if (connection == NULL) { | 446 if (connection == NULL) { |
123 g_assert(error); | 447 g_assert(error); |
124 gaim_debug_error("dbus", "Failed to open connection to bus: %s\n", | 448 gaim_debug_error("dbus", "Failed to open connection to bus: %s\n", |
125 error->message); | 449 error->message); |
126 g_error_free (error); | 450 g_error_free (error); |
127 return FALSE; | 451 return FALSE; |
128 } | 452 } |
129 | 453 |
130 | |
131 /* Instantiate the gaim dbus object and register it */ | 454 /* Instantiate the gaim dbus object and register it */ |
132 | 455 |
133 gaim_object = g_object_new (GAIM_TYPE_OBJECT, NULL); | 456 gaim_object = g_object_new (GAIM_TYPE_OBJECT, NULL); |
134 | 457 |
135 dbus_g_object_type_install_info (GAIM_TYPE_OBJECT, | 458 |
459 dbus_g_object_type_install_info (GAIM_TYPE_OBJECT, | |
136 &dbus_glib_gaim_object_object_info); | 460 &dbus_glib_gaim_object_object_info); |
137 | 461 |
138 dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM, | 462 dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM, |
139 gaim_object); | 463 gaim_object); |
140 | 464 |
141 | 465 |
142 /* Obtain a proxy for the DBus object */ | 466 /* Obtain a proxy for the DBus object */ |
143 | 467 |
144 driver_proxy = dbus_g_proxy_new_for_name (connection, | 468 driver_proxy = dbus_g_proxy_new_for_name (connection, |
145 DBUS_SERVICE_DBUS, | 469 DBUS_SERVICE_DBUS, |
146 DBUS_PATH_DBUS, | 470 DBUS_PATH_DBUS, |
147 DBUS_INTERFACE_DBUS); | 471 DBUS_INTERFACE_DBUS); |
148 | 472 |
473 g_assert(driver_proxy); | |
149 | 474 |
150 /* Test whether the registration was successful */ | 475 /* Test whether the registration was successful */ |
151 | 476 |
152 org_freedesktop_DBus_request_name(driver_proxy, DBUS_SERVICE_GAIM, | 477 org_freedesktop_DBus_request_name(driver_proxy, DBUS_SERVICE_GAIM, |
153 0, &request_name_ret, &error); | 478 DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &request_name_ret, &error); |
154 | 479 |
155 if (error) { | 480 if (error) { |
156 gaim_debug_error("dbus", "Failed to get name: %s\n", error->message); | 481 gaim_debug_error("dbus", "Failed to get name: %s\n", error->message); |
157 g_error_free (error); | 482 g_error_free (error); |
158 return FALSE; | 483 return FALSE; |
159 } | 484 } |
160 | 485 |
161 if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) | 486 if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) |
162 { | 487 { |
163 gaim_debug_error ("dbus", "Got result code %u from requesting name\n", | 488 gaim_debug_error ("dbus", "Got result code %u from requesting name\n", |
164 request_name_ret); | 489 request_name_ret); |
165 return FALSE; | 490 return FALSE; |
166 } | 491 } |
167 | 492 |
168 gaim_debug_misc ("dbus", "GLib test service has name '%s'\n", | 493 gaim_debug_misc ("dbus", "GLib test service has name '%s'\n", |
169 DBUS_SERVICE_GAIM); | 494 DBUS_SERVICE_GAIM); |
170 gaim_debug_misc ("dbus", "GLib test service entering main loop\n"); | 495 gaim_debug_misc ("dbus", "GLib test service entering main loop\n"); |
171 | 496 |
172 return TRUE; | 497 return TRUE; |
173 } | 498 } |