comparison src/dbus-server.c @ 11146:1c5398ccbeb0

[gaim-migrate @ 13217] Gaim-DBUS signal export works with DBUS >= 0.35 Various gaim API functions available through DBUS committer: Tailor Script <tailor@pidgin.im>
author Piotr Zielinski <zielaj>
date Fri, 22 Jul 2005 19:47:29 +0000
parents f54740547c95
children ebb02ea3c789
comparison
equal deleted inserted replaced
11145:dbc518c453f2 11146:1c5398ccbeb0
19 * along with this program; if not, write to the Free Software 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 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * 21 *
22 */ 22 */
23 23
24 #define DBUS_API_SUBJECT_TO_CHANGE
25
24 #include <dbus/dbus-glib.h> 26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
25 #include <dbus/dbus-glib-bindings.h> 28 #include <dbus/dbus-glib-bindings.h>
26 #include <stdio.h> 29 #include <stdio.h>
27 #include <stdlib.h> 30 #include <stdlib.h>
28 #include <string.h> 31 #include <string.h>
29 #include <glib/gi18n.h> 32 #include <glib/gi18n.h>
34 #include "account.h" 37 #include "account.h"
35 #include "blist.h" 38 #include "blist.h"
36 #include "conversation.h" 39 #include "conversation.h"
37 #include "dbus-gaim.h" 40 #include "dbus-gaim.h"
38 #include "dbus-server.h" 41 #include "dbus-server.h"
42 #include "dbus-useful.h"
39 #include "debug.h" 43 #include "debug.h"
40 #include "core.h" 44 #include "core.h"
41 #include "value.h" 45 #include "value.h"
42 46
43 static gint gaim_dbus_pointer_to_id(gpointer node);
44 static gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type);
45 47
46 48
47 /**************************************************************************/ 49 /**************************************************************************/
48 /** @name Lots of GObject stuff I don't really understand */ 50 /** @name Lots of GObject stuff I don't really understand */
49 /**************************************************************************/ 51 /**************************************************************************/
50 52
51 GType gaim_object_get_type(void); 53 GType gaim_object_get_type(void);
52 54
53 struct _GaimObject { 55 struct _GaimObject {
54 GObject parent; 56 GObject parent;
55 57 DBusGProxy *proxy;
56 int ping_signal_id;
57 }; 58 };
58 59
59 typedef struct { 60 typedef struct {
60 GObjectClass parent; 61 GObjectClass parent;
61 } GaimObjectClass; 62 } GaimObjectClass;
62
63 63
64 64
65 #define GAIM_DBUS_TYPE_OBJECT (gaim_object_get_type ()) 65 #define GAIM_DBUS_TYPE_OBJECT (gaim_object_get_type ())
66 #define GAIM_DBUS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GAIM_DBUS_TYPE_OBJECT, GaimObject)) 66 #define GAIM_DBUS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GAIM_DBUS_TYPE_OBJECT, GaimObject))
67 #define GAIM_DBUS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAIM_DBUS_TYPE_OBJECT, GaimObjectClass)) 67 #define GAIM_DBUS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAIM_DBUS_TYPE_OBJECT, GaimObjectClass))
72 G_DEFINE_TYPE(GaimObject, gaim_object, G_TYPE_OBJECT) 72 G_DEFINE_TYPE(GaimObject, gaim_object, G_TYPE_OBJECT)
73 73
74 GaimObject *gaim_dbus_object; 74 GaimObject *gaim_dbus_object;
75 static GQuark gaim_object_error_quark; 75 static GQuark gaim_object_error_quark;
76 76
77 #define NULLIFY(id) id = empty_to_null(id)
78
79 static const char* empty_to_null(const char *str) {
80 if (str == NULL || str[0] == 0)
81 return NULL;
82 else
83 return str;
84 }
85
77 static const char* null_to_empty(const char *s) { 86 static const char* null_to_empty(const char *s) {
78 if (s) 87 if (s)
79 return s; 88 return s;
80 else 89 else
81 return ""; 90 return "";
85 94
86 static void gaim_object_class_init(GaimObjectClass *klass) 95 static void gaim_object_class_init(GaimObjectClass *klass)
87 { 96 {
88 } 97 }
89 98
99 static void gaim_object_init(GaimObject *object)
100 {
101 }
102
103 /**************************************************************************/
104 /** @name Gaim DBUS pointer registration mechanism */
105 /**************************************************************************/
106
107 GaimDBusPointerType dbus_type_parent[DBUS_POINTER_LASTTYPE];
108
109 static GHashTable *map_id_node;
110 static GHashTable *map_id_type;
111 static GHashTable *map_node_id;
112
113
114 #define DECLARE_TYPE(type, parent) \
115 dbus_type_parent[DBUS_POINTER_##type] = DBUS_POINTER_##parent
116
117 void gaim_dbus_init_ids(void) {
118 int i;
119
120 map_id_node = g_hash_table_new (g_direct_hash, g_direct_equal);
121 map_id_type = g_hash_table_new (g_direct_hash, g_direct_equal);
122 map_node_id = g_hash_table_new (g_direct_hash, g_direct_equal);
123
124 for (i = 0; i < DBUS_POINTER_LASTTYPE; i++)
125 dbus_type_parent[i] = DBUS_POINTER_NONE;
126
127 /* some manual corrections */
128 DECLARE_TYPE(GaimBuddy, GaimBlistNode);
129 DECLARE_TYPE(GaimContact, GaimBlistNode);
130 DECLARE_TYPE(GaimChat, GaimBlistNode);
131 DECLARE_TYPE(GaimGroup, GaimBlistNode);
132 }
133
134 void gaim_dbus_register_pointer(gpointer node, GaimDBusPointerType type)
135 {
136 static gint last_id = 0;
137
138 g_assert(map_node_id);
139 g_assert(g_hash_table_lookup(map_node_id, node) == NULL);
140
141
142 last_id++;
143 g_hash_table_insert(map_node_id, node, GINT_TO_POINTER(last_id));
144 g_hash_table_insert(map_id_node, GINT_TO_POINTER(last_id), node);
145 g_hash_table_insert(map_id_type, GINT_TO_POINTER(last_id),
146 GINT_TO_POINTER(type));
147 }
148
149
150 void gaim_dbus_unregister_pointer(gpointer node) {
151 gpointer id = g_hash_table_lookup(map_node_id, node);
152
153 g_hash_table_remove(map_node_id, node);
154 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id));
155 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id));
156 }
157
158 static gint gaim_dbus_pointer_to_id(gpointer node) {
159 gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node));
160 g_return_val_if_fail(id, 0);
161 return id;
162 }
163
164 static gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type) {
165 GaimDBusPointerType objtype =
166 GPOINTER_TO_INT(g_hash_table_lookup(map_id_type,
167 GINT_TO_POINTER(id)));
168
169 while (objtype != type && objtype != DBUS_POINTER_NONE)
170 objtype = dbus_type_parent[objtype];
171
172 if (objtype == type)
173 return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id));
174 else
175 return NULL;
176 }
177
178 /**************************************************************************/
179 /** @name Useful functions */
180 /**************************************************************************/
181
182
183 #define error_unless_1(condition, str, parameter) \
184 if (!(condition)) { \
185 g_set_error(error, gaim_object_error_quark, \
186 DBUS_ERROR_NOT_FOUND, \
187 str, parameter); \
188 return FALSE; \
189 }
190
191 #define error_unless_2(condition, str, a,b) \
192 if (!(condition)) { \
193 g_set_error(error, gaim_object_error_quark, \
194 DBUS_ERROR_NOT_FOUND, \
195 str, a,b); \
196 return FALSE; \
197 }
198
199 #define GAIM_DBUS_ID_TO_POINTER(ptr, id, type) \
200 G_STMT_START { \
201 ptr = ((type*) gaim_dbus_id_to_pointer \
202 (id, DBUS_POINTER_##type)); \
203 error_unless_2(ptr != NULL || id == 0, \
204 "%s object with ID = %i not found", \
205 #type, id); \
206 } G_STMT_END
207
208
209 #define GAIM_DBUS_POINTER_TO_ID(id, ptr) \
210 G_STMT_START { \
211 gpointer _ptr = ptr; \
212 id = gaim_dbus_pointer_to_id(_ptr); \
213 error_unless_1(ptr == NULL || id != 0, \
214 "Result object not registered (%i)", \
215 id); \
216 } G_STMT_END
90 217
91 218
92 /**************************************************************************/ 219 /**************************************************************************/
93 /** @name Signals */ 220 /** @name Signals */
94 /**************************************************************************/ 221 /**************************************************************************/
95 222
96 /* used in #gaim_values_to_gvalues, undefined afterwards */ 223
97 #define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type)) 224
98 225 static char *gaim_dbus_convert_signal_name(const char *gaim_name)
99 /**
100 Converts from a list of data into an GValue array.
101
102 @param gvalus Array of empty gvalues to be filled.
103 @param number The number of data items.
104 @param gaim_value Array of #number pointers to GaimValues.
105 The types of of these GaimValues determine the type
106 of data items. The values do not matter.
107 @param mainptr A pointer to a single data item. If this pointer is not #NULL,
108 then #number must be 1.
109 @param data A va_list containing data items. If
110
111 Exactly one of #mainptr and #data must be not #NULL. If #mainptr
112 is not #NULL, then there is a single piece of data at the address
113 pointed at by #mainptr. If #data is not #NULL, then there are
114 #number data items in the #va_list #data.
115 */
116 static void gaim_values_to_gvalues(GValue *gvalue, int number,
117 GaimValue **gaim_values, gpointer mainptr, va_list data)
118 {
119 int i;
120 gpointer ptr;
121
122 g_assert(mainptr == NULL || data == NULL);
123 g_assert(mainptr != NULL || data != NULL);
124 g_assert(number == 1 || data != NULL);
125
126 for(i=0; i<number; i++, gvalue++) {
127 ptr = mainptr;
128 if (gaim_value_is_outgoing(gaim_values[i])) {
129 ptr = my_arg(gpointer);
130 g_assert(ptr);
131 }
132
133 switch(gaim_values[i]->type) {
134 case GAIM_TYPE_CHAR:
135 g_value_init(gvalue, G_TYPE_CHAR);
136 g_value_set_char(gvalue, (char) my_arg(int));
137 break;
138 case GAIM_TYPE_INT:
139 g_value_init(gvalue, G_TYPE_INT);
140 g_value_set_int(gvalue, my_arg(gint));
141 break;
142 case GAIM_TYPE_UINT:
143 g_value_init(gvalue, G_TYPE_UINT);
144 g_value_set_uint(gvalue, my_arg(guint));
145 break;
146 case GAIM_TYPE_BOOLEAN:
147 g_value_init(gvalue, G_TYPE_BOOLEAN);
148 g_value_set_boolean(gvalue, my_arg(gboolean));
149 break;
150 case GAIM_TYPE_STRING:
151 g_value_init(gvalue, G_TYPE_STRING);
152 g_value_set_string(gvalue, null_to_empty(my_arg(char*)));
153 break;
154 case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
155 g_value_init(gvalue, G_TYPE_INT);
156 g_value_set_int(gvalue,
157 gaim_dbus_pointer_to_id(my_arg(gpointer)));
158 break;
159 case GAIM_TYPE_POINTER:
160 case GAIM_TYPE_OBJECT:
161 case GAIM_TYPE_BOXED:
162 my_arg(gpointer); /* cannot pass general pointers */
163 g_value_init(gvalue, G_TYPE_INT);
164 g_value_set_int(gvalue, 0);
165 break;
166
167 default: /* no conversion implemented */
168 g_assert_not_reached();
169 }
170 }
171
172 if (data)
173 va_end(data);
174 }
175
176 #undef my_arg /* my_arg was only used in gaim_values_to_gvalues */
177
178
179
180 /**
181 Converts from GaimTypes to GTypes.
182
183 @param type A GaimType to be converted.
184 @result The result of the conversion (GType).
185 */
186 static GType gaim_type_to_g_type(GaimType type)
187 {
188 switch(type) {
189 case GAIM_TYPE_CHAR:
190 return G_TYPE_CHAR;
191 case GAIM_TYPE_INT:
192 return G_TYPE_INT;
193 case GAIM_TYPE_UINT:
194 return G_TYPE_UINT;
195 case GAIM_TYPE_BOOLEAN:
196 return G_TYPE_BOOLEAN;
197 case GAIM_TYPE_STRING:
198 return G_TYPE_STRING;
199 case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
200 return G_TYPE_INT;
201 case GAIM_TYPE_POINTER:
202 case GAIM_TYPE_BOXED:
203 case GAIM_TYPE_OBJECT:
204 return G_TYPE_INT; /* always 0 */
205 default: /* no conversion implemented */
206 g_assert_not_reached();
207 }
208 }
209
210
211 static const char *gaim_dbus_convert_signal_name(const char *gaim_name)
212 { 226 {
213 int gaim_index, g_index; 227 int gaim_index, g_index;
214 char *g_name = g_new(char, strlen(gaim_name)+1); 228 char *g_name = g_new(char, strlen(gaim_name)+1);
215 gboolean capitalize_next = TRUE; 229 gboolean capitalize_next = TRUE;
216 230
226 g_name[g_index] = 0; 240 g_name[g_index] = 0;
227 241
228 return g_name; 242 return g_name;
229 } 243 }
230 244
231 /* Public signal-related functions */ 245 #define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type))
232 246
233 247 static void gaim_dbus_message_append_gaim_values(DBusMessageIter *iter,
234 void gaim_dbus_invalid_marshaller(GClosure *closure, 248 int number,
235 GValue *return_value, 249 GaimValue **gaim_values,
236 guint n_param_values, 250 va_list data)
237 const GValue *param_values, 251 {
238 gpointer invocation_hint, 252 int i;
239 gpointer marshal_data) 253
240 { 254 for(i=0; i<number; i++) {
241 g_assert_not_reached(); 255 const char *str;
242 } 256 int id;
243 257 gint xint;
244 int gaim_dbus_signal_register(GaimObject *object, const char *name, 258 guint xuint;
245 GSignalCMarshaller marshaller, 259 gboolean xboolean;
246 int num_values, ...) 260 gpointer ptr = NULL;
247 { 261 if (gaim_value_is_outgoing(gaim_values[i])) {
248 va_list args; 262 ptr = my_arg(gpointer);
249 263 g_assert(ptr);
250 va_start(args, num_values); 264 }
251 265
252 return g_signal_new_valist(name, G_OBJECT_TYPE(object), 266 switch(gaim_values[i]->type) {
253 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 267 case GAIM_TYPE_INT:
254 NULL, NULL, NULL, marshaller, 268 g_print("appending int\n");
255 G_TYPE_NONE, num_values, args); 269 xint = my_arg(gint);
256 } 270 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint);
257 271 break;
258 void gaim_dbus_signal_emit(GaimObject *object, int dbus_id, ...) { 272 case GAIM_TYPE_UINT:
259 va_list args; 273 xuint = my_arg(guint);
260 274 g_print("appending uint\n");
261 va_start(args, dbus_id); 275 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint);
262 276 break;
263 gaim_dbus_signal_emit_valist(object, dbus_id, args); 277 case GAIM_TYPE_BOOLEAN:
264 } 278 g_print("appending boolean\n");
265 279 xboolean = my_arg(gboolean);
266 void gaim_dbus_signal_emit_valist(GaimObject *object, int dbus_id, va_list args) { 280 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean);
267 g_signal_emit_valist(object, dbus_id, 0, args); 281 break;
268 } 282 case GAIM_TYPE_STRING:
269 283 g_print("appending string\n");
270 int gaim_dbus_signal_register_gaim(GaimObject *object, const char *name, 284 str = null_to_empty(my_arg(char*));
271 GSignalCMarshaller marshaller, 285 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
272 int num_values, GaimValue **values) 286 break;
273 { 287 case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
274 int i; 288 case GAIM_TYPE_POINTER:
275 int dbus_id; 289 case GAIM_TYPE_OBJECT:
276 GType *types; 290 case GAIM_TYPE_BOXED:
277 291 g_print("appending obj\n");
278 types = g_new0(GType, num_values); 292 id = gaim_dbus_pointer_to_id(my_arg(gpointer));
279 293 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &id);
280 for(i=0; i<num_values; i++) 294 break;
281 types[i] = gaim_type_to_g_type(values[i]->type); 295 default: /* no conversion implemented */
282 296 g_assert_not_reached();
283 dbus_id = 297 }
284 g_signal_newv(gaim_dbus_convert_signal_name(name), 298 }
285 G_OBJECT_TYPE(object), 299 }
286 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 300
287 NULL, NULL, NULL, marshaller, 301 #undef my_arg
288 G_TYPE_NONE, num_values, types); 302
289 303 void gaim_dbus_signal_emit_gaim(GaimObject *object, char *name, int num_values,
290 g_free(types);
291
292 return dbus_id;
293 }
294
295
296 void gaim_dbus_signal_emit_gaim(GaimObject *object, int dbus_id, int num_values,
297 GaimValue **values, va_list vargs) 304 GaimValue **values, va_list vargs)
298 { 305 {
299 GValue *args; 306 /* pass name */
300 int i; 307 DBusMessage *signal;
301 308 DBusMessageIter iter;
302 g_return_if_fail(dbus_id); 309 char *newname;
303 310
304 args = g_new0(GValue, num_values + 1); 311 g_print("Emitting %s\n", name);
305 312 g_return_if_fail(object->proxy);
306 g_value_init(args + 0, G_OBJECT_TYPE(object)); 313
307 g_value_set_object(args + 0, object); 314 newname = gaim_dbus_convert_signal_name(name);
308 315 signal = dbus_message_new_signal(DBUS_PATH_GAIM, DBUS_INTERFACE_GAIM, newname);
309 gaim_values_to_gvalues(args + 1, num_values, values, NULL, vargs); 316 dbus_message_iter_init_append(signal, &iter);
310 317
311 g_signal_emitv(args, dbus_id, 0, NULL); 318 gaim_dbus_message_append_gaim_values(&iter, num_values, values, vargs);
312 319
313 for(i = 1; i <= num_values; i++) 320 dbus_g_proxy_send(object->proxy, signal, NULL);
314 g_value_unset(args + i); 321
315 322 g_free(newname);
316 g_free(args); 323 dbus_message_unref(signal);
317 } 324 }
318 325
319 326
320 /**************************************************************************/ 327 /**************************************************************/
321 /** @name Utility functions */ 328 /* DBus bindings ... */
322 /**************************************************************************/ 329 /**************************************************************/
323 330
324 #define error_unless_1(condition, str, parameter) \ 331
325 if (!(condition)) { \ 332
326 g_set_error(error, gaim_object_error_quark, \ 333 GArray* gaim_dbusify_GList(GList *list, gboolean free_memory) {
327 DBUS_ERROR_NOT_FOUND, \ 334 GArray *array;
328 str, parameter); \ 335 GList *elem;
329 return FALSE; \ 336
330 } 337 array = g_array_new (FALSE, TRUE, sizeof (guint32));
331 338 for(elem = list; elem != NULL; elem = elem->next) {
332 #define error_unless_2(condition, str, a,b) \ 339 int objectid;
333 if (!(condition)) { \ 340
334 g_set_error(error, gaim_object_error_quark, \ 341 objectid = gaim_dbus_pointer_to_id(elem->data);
335 DBUS_ERROR_NOT_FOUND, \ 342 g_array_append_val(array, objectid);
336 str, a,b); \ 343 }
337 return FALSE; \ 344
338 } 345 if (free_memory)
339 346 g_list_free(list);
340 typedef gboolean (*GaimNodeFilter)(GaimBlistNode *node, gpointer *user_data); 347
341 348 return array;
342 static gboolean 349 }
343 filter_is_buddy(GaimBlistNode *node, gpointer *user_data) 350
344 { 351 GArray* gaim_dbusify_GSList(GSList *list, gboolean free_memory) {
345 return GAIM_BLIST_NODE_IS_BUDDY(node); 352 GArray *array;
346 } 353 GSList *elem;
347 354
348 static gboolean 355 array = g_array_new (FALSE, TRUE, sizeof (guint32));
349 filter_is_online_buddy(GaimBlistNode *node, 356 for(elem = list; elem != NULL; elem = elem->next) {
350 gpointer *user_data) 357 int objectid;
351 { 358
352 return GAIM_BLIST_NODE_IS_BUDDY(node) && 359 objectid = gaim_dbus_pointer_to_id(elem->data);
353 GAIM_BUDDY_IS_ONLINE((GaimBuddy *)node); 360 g_array_append_val(array, objectid);
354 } 361 }
355 362
356 363 if (free_memory)
357 static GList* 364 g_slist_free(list);
358 get_buddy_list (GList *created_list, /**< can be NULL */ 365 return array;
359 GaimBlistNode *gaim_buddy_list, /**< can be NULL */ 366 }
360 GaimNodeFilter filter, 367
361 gpointer user_data) 368 #include "dbus-generated-code.c"
362 {
363 GaimBlistNode *node;
364
365 for(node = gaim_buddy_list; node; node = node->next)
366 {
367 if ((*filter)(node, user_data))
368 created_list = g_list_prepend(created_list, node);
369
370 created_list = get_buddy_list(created_list, node->child,
371 filter, user_data);
372 }
373
374 return created_list;
375 }
376
377
378
379 /**************************************************************************/
380 /** @name Implementations of remote DBUS calls */
381 /**************************************************************************/
382
383 static gboolean
384 gaim_object_ping(GaimObject *object, GError **error)
385 {
386 gaim_dbus_signal_emit(object, object->ping_signal_id, "Ping Pong!");
387 return TRUE;
388 }
389
390 static gboolean
391 gaim_object_quit(GaimObject *obj, GError **error)
392 {
393 g_timeout_add(0, gaim_core_quit_cb, NULL);
394 return TRUE;
395 }
396
397 static gboolean
398 gaim_object_connect_all(GaimObject *obj, GError **error)
399 {
400 GList *cur;
401
402 for (cur = gaim_accounts_get_all(); cur != NULL; cur = cur->next)
403 gaim_account_connect((GaimAccount*) cur->data);
404
405 return TRUE;
406 }
407
408
409
410 static gboolean
411 gaim_object_get_buddy_list (GaimObject *obj, GArray **out_buddy_ids,
412 GError **error)
413 {
414 GList *node;
415 GList *buddy_list = get_buddy_list(NULL, gaim_get_blist()->root,
416 &filter_is_buddy, NULL);
417 GArray *buddy_ids = g_array_new(FALSE, TRUE, sizeof(gint32));;
418
419 buddy_list = g_list_reverse(buddy_list);
420
421 for (node = buddy_list; node; node = node->next) {
422 gint32 id = gaim_dbus_pointer_to_id(node->data);
423 g_array_append_val(buddy_ids, id);
424 }
425
426 g_list_free(buddy_list);
427 *out_buddy_ids = buddy_ids;
428
429 return TRUE;
430 }
431
432
433
434
435
436 static gboolean
437 gaim_object_find_account(GaimObject *object,
438 const char *account_name, const char *protocol_name,
439 gint *account_id, GError **error)
440 {
441 GaimAccount *account = gaim_accounts_find(account_name, protocol_name);
442
443 error_unless_2(account, "Account '%s' with protocol '%s' not found",
444 account_name, protocol_name);
445
446 *account_id = gaim_dbus_pointer_to_id(account);
447 return TRUE;
448 }
449
450 static gboolean
451 gaim_object_find_buddy(GaimObject *object, gint account_id, const char *buddy_name,
452 gint *buddy_id, GError **error)
453 {
454 GaimAccount *account;
455 GaimBuddy *buddy;
456
457 account = gaim_dbus_id_to_pointer(account_id, DBUS_POINTER_ACCOUNT);
458 error_unless_1(account, "Invalid account id: %i", account_id);
459
460 buddy = gaim_find_buddy(account, buddy_name);
461 error_unless_1(account, "Buddy '%s' not found.", buddy_name);
462
463 *buddy_id = gaim_dbus_pointer_to_id(buddy);
464 return TRUE;
465 }
466
467 static gboolean
468 gaim_object_start_im_conversation (GaimObject *object, gint buddy_id, GError **error)
469 {
470 GaimBuddy *buddy = (GaimBuddy*) gaim_dbus_id_to_pointer(buddy_id,
471 DBUS_POINTER_BUDDY);
472
473 error_unless_1(buddy, "Invalid buddy id: %i", buddy_id);
474
475 gaim_conversation_new(GAIM_CONV_IM, buddy->account, buddy->name);
476
477 return TRUE;
478 }
479
480
481
482 /**************************************************************************/
483 /** @name Gaim DBUS property handling functions */
484 /**************************************************************************/
485
486
487 typedef struct _GaimDBusProperty {
488 char *name;
489 gint offset;
490 GaimType type;
491 } GaimDBusProperty;
492
493 /* change GAIM_TYPE into G_TYPE */
494
495 static gboolean
496 gaim_dbus_get_property(GaimDBusProperty *list, int list_len,
497 gpointer data, const char *name,
498 GValue *value, GError **error)
499 {
500 int i;
501
502 for(i=0; i<list_len; i++) {
503 if (!strcmp(list[i].name, name)) {
504 gpointer ptr;
505 GaimValue gaim_value, *gaim_value_ptr;
506
507 ptr = G_STRUCT_MEMBER_P(data, list[i].offset);
508 gaim_value.type = list[i].type;
509 gaim_value.flags = 0;
510 gaim_value_ptr = &gaim_value;
511
512 gaim_values_to_gvalues(value, 1, &gaim_value_ptr,
513 ptr, NULL);
514 return TRUE;
515 }
516 }
517
518 g_value_init(value, G_TYPE_INT);
519 g_value_set_int(value, 0);
520 error_unless_1(FALSE, "Invalid property '%s'", name);
521 }
522
523
524 #define DECLARE_PROPERTY(maintype, name, type) {#name, G_STRUCT_OFFSET(maintype, name), type}
525
526 GaimDBusProperty buddy_properties [] = {
527 DECLARE_PROPERTY(GaimBuddy, name, GAIM_TYPE_STRING),
528 DECLARE_PROPERTY(GaimBuddy, alias, GAIM_TYPE_STRING),
529 DECLARE_PROPERTY(GaimBuddy, server_alias, GAIM_TYPE_STRING),
530 DECLARE_PROPERTY(GaimBuddy, account, GAIM_TYPE_SUBTYPE)
531 };
532
533 GaimDBusProperty account_properties [] = {
534 DECLARE_PROPERTY(GaimAccount, username, GAIM_TYPE_STRING),
535 DECLARE_PROPERTY(GaimAccount, alias, GAIM_TYPE_STRING),
536 DECLARE_PROPERTY(GaimAccount, user_info, GAIM_TYPE_STRING),
537 DECLARE_PROPERTY(GaimAccount, protocol_id, GAIM_TYPE_STRING),
538 };
539
540 GaimDBusProperty contact_properties [] = {
541 DECLARE_PROPERTY(GaimContact, alias, GAIM_TYPE_STRING),
542 DECLARE_PROPERTY(GaimContact, totalsize, GAIM_TYPE_INT),
543 DECLARE_PROPERTY(GaimContact, currentsize, GAIM_TYPE_INT),
544 DECLARE_PROPERTY(GaimContact, online, GAIM_TYPE_INT),
545 DECLARE_PROPERTY(GaimContact, priority, GAIM_TYPE_SUBTYPE),
546 DECLARE_PROPERTY(GaimContact, priority_valid, GAIM_TYPE_BOOLEAN),
547 };
548
549 GaimDBusProperty group_properties [] = {
550 DECLARE_PROPERTY(GaimGroup, name, GAIM_TYPE_STRING),
551 DECLARE_PROPERTY(GaimGroup, totalsize, GAIM_TYPE_INT),
552 DECLARE_PROPERTY(GaimGroup, currentsize, GAIM_TYPE_INT),
553 DECLARE_PROPERTY(GaimGroup, online, GAIM_TYPE_INT),
554 };
555
556 GaimDBusProperty chat_properties [] = {
557 DECLARE_PROPERTY(GaimChat, alias, GAIM_TYPE_STRING),
558 DECLARE_PROPERTY(GaimChat, account, GAIM_TYPE_SUBTYPE),
559 };
560
561
562 #define DECLARE_PROPERTY_HANDLER(type, gaim_type) \
563 static gboolean \
564 gaim_object_get_##type##_property (GaimObject *object, \
565 gint id, const char *property_name, \
566 GValue *value, GError **error) \
567 { \
568 gpointer ptr = gaim_dbus_id_to_pointer(id, gaim_type); \
569 \
570 error_unless_1(ptr, "Invalid " #type " id: %i", id); \
571 \
572 return gaim_dbus_get_property(type##_properties, \
573 G_N_ELEMENTS(type##_properties), \
574 ptr, property_name, value, error); \
575 }
576
577 DECLARE_PROPERTY_HANDLER(buddy, DBUS_POINTER_BUDDY)
578 DECLARE_PROPERTY_HANDLER(account, DBUS_POINTER_ACCOUNT)
579 DECLARE_PROPERTY_HANDLER(contact, DBUS_POINTER_CONTACT)
580 DECLARE_PROPERTY_HANDLER(group, DBUS_POINTER_GROUP)
581 DECLARE_PROPERTY_HANDLER(chat, DBUS_POINTER_CHAT)
582 369
583 #include "dbus-server-bindings.c" 370 #include "dbus-server-bindings.c"
584 371
585 372
586 373
587 /**************************************************************************/
588 /** @name Gaim DBUS pointer registration mechanism */
589 /**************************************************************************/
590
591 static GHashTable *map_id_node;
592 static GHashTable *map_id_type;
593 static GHashTable *map_node_id;
594
595 void gaim_dbus_init_ids(void) {
596
597
598 map_id_node = g_hash_table_new (g_direct_hash, g_direct_equal);
599 map_id_type = g_hash_table_new (g_direct_hash, g_direct_equal);
600 map_node_id = g_hash_table_new (g_direct_hash, g_direct_equal);
601 }
602
603 void gaim_dbus_register_pointer(gpointer node, GaimDBusPointerType type)
604 {
605 static gint last_id = 0;
606
607 g_assert(map_node_id);
608 g_assert(g_hash_table_lookup(map_node_id, node) == NULL);
609
610
611 last_id++;
612 g_hash_table_insert(map_node_id, node, GINT_TO_POINTER(last_id));
613 g_hash_table_insert(map_id_node, GINT_TO_POINTER(last_id), node);
614 g_hash_table_insert(map_id_type, GINT_TO_POINTER(last_id),
615 GINT_TO_POINTER(type));
616 }
617
618
619 void gaim_dbus_unregister_pointer(gpointer node) {
620 gpointer id = g_hash_table_lookup(map_node_id, node);
621
622 g_hash_table_remove(map_node_id, node);
623 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id));
624 g_hash_table_remove(map_id_node, GINT_TO_POINTER(id));
625 }
626
627 static gint gaim_dbus_pointer_to_id(gpointer node) {
628 g_assert(map_node_id);
629
630 gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node));
631 g_return_val_if_fail(id, 0);
632 return id;
633 }
634
635 static gpointer gaim_dbus_id_to_pointer(gint id, GaimDBusPointerType type) {
636 if (type != GPOINTER_TO_INT(g_hash_table_lookup(map_id_type,
637 GINT_TO_POINTER(id))))
638 return NULL;
639 return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id));
640 }
641
642 374
643 375
644 /**************************************************************************/ 376 /**************************************************************************/
645 /** @name Gaim DBUS init function */ 377 /** @name Gaim DBUS init function */
646 /**************************************************************************/ 378 /**************************************************************************/
647 379
380
381 /* fixme: why do we need two functions here instead of one? */
648 382
649 gboolean gaim_dbus_connect(GaimObject *object) 383 gboolean gaim_dbus_connect(GaimObject *object)
650 { 384 {
651 DBusGConnection *connection; 385 DBusGConnection *connection;
652 GError *error = NULL; 386 GError *error = NULL;
653 DBusGProxy *driver_proxy; 387 DBusGProxy *driver_proxy;
654 guint32 request_name_ret; 388 guint32 request_name_ret;
655 389
656
657 gaim_debug_misc("dbus", "launching dbus server\n"); 390 gaim_debug_misc("dbus", "launching dbus server\n");
658 391
659 /* Connect to the bus */ 392 dbus_g_object_type_install_info (GAIM_DBUS_TYPE_OBJECT,
393 &dbus_glib_gaim_object_object_info); /* Connect to the bus */
660 394
661 error = NULL; 395 error = NULL;
662 connection = dbus_g_bus_get(DBUS_BUS_STARTER, &error); 396 connection = dbus_g_bus_get(DBUS_BUS_STARTER, &error);
663 397
664 if (connection == NULL) { 398 if (connection == NULL) {
672 /* Instantiate the gaim dbus object and register it */ 406 /* Instantiate the gaim dbus object and register it */
673 407
674 408
675 409
676 410
677 dbus_g_object_type_install_info (GAIM_DBUS_TYPE_OBJECT,
678 &dbus_glib_gaim_object_object_info);
679
680 dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM,
681 (GObject*) object);
682
683
684 /* Obtain a proxy for the DBus object */ 411 /* Obtain a proxy for the DBus object */
685 412
686 driver_proxy = dbus_g_proxy_new_for_name (connection, 413 driver_proxy = dbus_g_proxy_new_for_name (connection,
687 DBUS_SERVICE_DBUS, 414 DBUS_SERVICE_DBUS,
688 DBUS_PATH_DBUS, 415 DBUS_PATH_DBUS,
708 return FALSE; 435 return FALSE;
709 } 436 }
710 437
711 gaim_debug_misc ("dbus", "GLib test service has name '%s'\n", 438 gaim_debug_misc ("dbus", "GLib test service has name '%s'\n",
712 DBUS_SERVICE_GAIM); 439 DBUS_SERVICE_GAIM);
440
441
442
443 dbus_g_connection_register_g_object (connection, DBUS_PATH_GAIM,
444 (GObject*) object);
445
446 object->proxy = dbus_g_proxy_new_for_name (connection,
447 DBUS_SERVICE_GAIM,
448 DBUS_PATH_GAIM,
449 DBUS_INTERFACE_GAIM);
450
713 gaim_debug_misc ("dbus", "GLib test service entering main loop\n"); 451 gaim_debug_misc ("dbus", "GLib test service entering main loop\n");
714 452
715 return TRUE; 453 return TRUE;
716 } 454 }
717 455
718 456
719 static void gaim_object_init(GaimObject *object)
720 {
721
722 object->ping_signal_id =
723 gaim_dbus_signal_register(object, "PingSignal",
724 g_cclosure_marshal_VOID__STRING,
725 1, G_TYPE_STRING);
726 }
727 457
728 458
729 gboolean gaim_dbus_init(void) 459 gboolean gaim_dbus_init(void)
730 { 460 {
731 gaim_dbus_init_ids(); 461 gaim_dbus_init_ids();
732 gaim_object_error_quark = 462 gaim_object_error_quark =
733 g_quark_from_static_string("org.gaim.GaimError"); 463 g_quark_from_static_string("org.gaim.GaimError");
464
465
734 466
735 gaim_dbus_object = GAIM_DBUS_OBJECT(g_object_new (GAIM_DBUS_TYPE_OBJECT, NULL)); 467 gaim_dbus_object = GAIM_DBUS_OBJECT(g_object_new (GAIM_DBUS_TYPE_OBJECT, NULL));
736 468
469 gaim_dbus_object->proxy = NULL;
737 return TRUE; 470 return TRUE;
738 } 471 }
472
473