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 }