Mercurial > pidgin
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 |